【備忘】初心者がつまづくJS
はじめに
最近、インターンシップを通じて学生にアプリ開発体験をしてもらう機会がありました。
JS + React
を使った小さなアプリを2日で作り上げるといったものですが、参加にあたり選考を行っていないので当然、プログラミングへの理解には個人差があります。
そのあたりは当然認識していたので、なるべく初学者にも分かるように平易な内容の資料を作って説明をしたのですが、こちらが意図しない箇所でつまづいている事が何回かあったので、今後の備忘もかねて記事にしたいと思います。
新卒で未経験者を採用する機会もあるので、教育担当をされる方にも参考になるのではないかと思います。
前提とする初心者
プログラミングへの理解に差異があるといっても、大学や専門学校で情報系の講義やゼミを受講しているものとします。
そういった意味では完全な初心者ではありませんので、ご了承ください。
以下のようなスキル・知識レベルを持っている方とします。
- 何かしらの言語をかじったことがある(今回の場合、
C
とJava
でした) -
JS
を知らない -
HTML
はなんとなく見たことがある
「プログラミング基礎」のような講義で扱われるためC
やJava
を触ったことがある方が多いのかなと思います。
そのため、簡単な四則演算やアルゴリズム、オブジェクト思考などの話はある程度理解しているようでした。
つまづいた箇所
React
に関してはハマることが予想されていたので、jQuery
を使ってDOM
をゴリゴリいじっていた頃の話から順に、仮想DOM
になった経緯を交えて丁寧に話したので意外とつまづくことはありませんでした。
敢えて挙げるならsetState
をせず、this.state.hoge = "aaa"
のように、直接state
をいじってしまうケースがありましたが、ここでは割愛しています。
配列操作
配列に値を追加するpush
は直感的だったので理解しやすそうでしたが、要素の上書きや削除でハマっている方が多かったです。
既に学習済みの言語であるC
やJava
と文法的に違いはなさそうなので、自分としても「?」でした。
要素の削除はfilter
やreduce
を使っても同じことができますが、今回はsplice
を使うことにしました。
// 4番目の要素を上書き
let foo = [1,2,3,4,5];
foo[3] = 100;
// --> [1,2,3,100,5]
// 4番目の要素を削除
let bar = ["a","b","c","d","e"];
bar.splice(3,1);
// --> ["a","b","c","e"];
// filterを使ってもよいが、spliceの方が直感的?だった印象
ちなみにsplice
は戻り値として「抜き出された要素の配列」が返ってきます。
コンソール上で実際に戻り値とsplice
された後の配列を見せながら「配列から一部要素を抜き出す関数」であることを説明して、その性質を応用して「擬似的に要素の削除を行っている」という風に話すと理解してもらえました。
日付操作
日付で特につまづいたのはgetDay
やgetMonth
です。
getDay
に関しては、そもそもgetDate
と混同してしまうケースが多かったです(たまに自分も分からなくなるので、ある程度は仕方ないと思います)。
この2つがどうしてハマりやすいのかというと、戻り値が0
から始まるからです。
// 今日の日付
const today = new Date();
const dayKind = today.getDay();
// --> 0:Sun, 1:Mon, 2:Tue, 3:Wed, 4:Thr, 5:Fri, 6:Sat
const yesterday = new Date(2020,11,15);
const monthKind = today.getMonth();
// --> 0:Jan, 1:Feb, 2:Mar, 3:Apr, 4:May, 5:Jun, 6:Jul, 7:Aug, 8:Sep, 9:Oct, 10:Nov, 11:Dec
上記の例のようにgetMonth
の結果は0
が1月、1
が2月・・・と続いていきます。
対してgetFullYear
は2020年なら2020
とそのままの値が返ってくるので、この辺りの仕様が混乱を招いていたのだと思います。
先ほどの配列のインデックスの話もそうですが、どうも「0
から数え始める」というのに違和感を覚えていた様子でした。
日常的にプログラムに触れていないと、この辺りのお作法的な部分が引っかかるのかもしれません。
参照渡し
配列やオブジェクトを扱っていく時に、直接変数に代入すると下記のように代入した側もされた側も値が変わっていまいます。
let foo = [1,2,3];
let bar = foo;
console.log(foo);
// --> [1,2,3]
console.log(bar);
// --> [1,2,3]
foo.push(4);
console.log(foo);
// --> [1,2,3,4]
console.log(bar);
// --> [1,2,3,4]
このあたりは 「そもそもプリミティブ型とオブジェクト型というものがあって・・・」 といった所から説明する必要があり、理解してもらうのになかなか時間がかかりました。
また、最終的な解決策としてスプレッド演算子を使った方法を紹介しましたが、これまたJS
固有の記法なので頭にスッと入ってこない様子でした。
// スプレッド演算子
let foo = [1,2,3];
let bar = [...foo];
foo.push(4);
console.log(foo);
// --> [1,2,3,4]
console.log(bar);
// --> [1,2,3]
後から思ったのですが、Array.from
やconcat
の方が理解しやすかったのかもしれません・・・
// Array.from
let foo = [1,2,3];
let bar = Array.from(foo);
foo.push(4);
console.log(foo);
// --> [1,2,3,4]
console.log(bar);
// --> [1,2,3]
// concat
let foo = [1,2,3];
let bar = foo.concat();
foo.push(4);
console.log(foo);
// --> [1,2,3,4]
console.log(bar);
// --> [1,2,3]
2022/05/02追記
しぐ煮さんより下記リンクを共有いただきました。
本記事での「参照渡し」はオフィシャルな言葉ではなく、それに近い挙動をしているため便宜上「参照渡し」と呼称しているものとします。
まとめ
今回は実際の経験をもとに、JS
をはじめて学習する方がハマる箇所をいくつか紹介しました。
細かいところを挙げていくともう少しあるのですが、大きくつまづいたものだけピックアップしました。
「初心者の気持ちは初心者である頃にしか分からない」 という言葉をどこかで聞いたことがありますが、まさにそうだと思いました。
あれこれ考察をして「これこれこういう考え方をするから理解しにくいんだろう」と理由づけることはできますが、実際のところハマる理由は千差万別です。
また、分からない場合に「こういう理由で分からない」と言語化するのはなかなか難しいものです。
全体を通して感じたのは、そういった場合は実際に関数や処理を実行してみせて値や実行結果がどう変化していくかを順番に確認していくことが有効でした。
口頭や文字で理屈を説明されるより、動いているものを見ながらの方が頭に入ってきやすいようです。
初心者の方に教える際は、上記を意識するといいのかなと思います。
Discussion
ありがとうございます!
追記しました!