🗒️

【備忘】初心者がつまづくJS

2020/12/21に公開
2

はじめに

最近、インターンシップを通じて学生にアプリ開発体験をしてもらう機会がありました。
JS + Reactを使った小さなアプリを2日で作り上げるといったものですが、参加にあたり選考を行っていないので当然、プログラミングへの理解には個人差があります。

そのあたりは当然認識していたので、なるべく初学者にも分かるように平易な内容の資料を作って説明をしたのですが、こちらが意図しない箇所でつまづいている事が何回かあったので、今後の備忘もかねて記事にしたいと思います。

新卒で未経験者を採用する機会もあるので、教育担当をされる方にも参考になるのではないかと思います。

前提とする初心者

プログラミングへの理解に差異があるといっても、大学や専門学校で情報系の講義やゼミを受講しているものとします。
そういった意味では完全な初心者ではありませんので、ご了承ください。
以下のようなスキル・知識レベルを持っている方とします。

  • 何かしらの言語をかじったことがある(今回の場合、CJavaでした)
  • JSを知らない
  • HTMLはなんとなく見たことがある

「プログラミング基礎」のような講義で扱われるためCJavaを触ったことがある方が多いのかなと思います。
そのため、簡単な四則演算やアルゴリズム、オブジェクト思考などの話はある程度理解しているようでした。

つまづいた箇所

Reactに関してはハマることが予想されていたので、jQueryを使ってDOMをゴリゴリいじっていた頃の話から順に、仮想DOMになった経緯を交えて丁寧に話したので意外とつまづくことはありませんでした。
敢えて挙げるならsetStateをせず、this.state.hoge = "aaa"のように、直接stateをいじってしまうケースがありましたが、ここでは割愛しています。

配列操作

配列に値を追加するpushは直感的だったので理解しやすそうでしたが、要素の上書きや削除でハマっている方が多かったです。
既に学習済みの言語であるCJavaと文法的に違いはなさそうなので、自分としても「?」でした。
要素の削除はfilterreduceを使っても同じことができますが、今回は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は戻り値として「抜き出された要素の配列」が返ってきます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

コンソール上で実際に戻り値とspliceされた後の配列を見せながら「配列から一部要素を抜き出す関数」であることを説明して、その性質を応用して「擬似的に要素の削除を行っている」という風に話すと理解してもらえました。

日付操作

日付で特につまづいたのはgetDaygetMonthです。
getDayに関しては、そもそもgetDateと混同してしまうケースが多かったです(たまに自分も分からなくなるので、ある程度は仕方ないと思います)。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getMonth

この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.fromconcatの方が理解しやすかったのかもしれません・・・

// 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追記

しぐ煮さんより下記リンクを共有いただきました。
https://qiita.com/yuta0801/items/f8690a6e129c594de5fb

本記事での「参照渡し」はオフィシャルな言葉ではなく、それに近い挙動をしているため便宜上「参照渡し」と呼称しているものとします。

まとめ

今回は実際の経験をもとに、JSをはじめて学習する方がハマる箇所をいくつか紹介しました。
細かいところを挙げていくともう少しあるのですが、大きくつまづいたものだけピックアップしました。

「初心者の気持ちは初心者である頃にしか分からない」 という言葉をどこかで聞いたことがありますが、まさにそうだと思いました。
あれこれ考察をして「これこれこういう考え方をするから理解しにくいんだろう」と理由づけることはできますが、実際のところハマる理由は千差万別です。
また、分からない場合に「こういう理由で分からない」と言語化するのはなかなか難しいものです。

全体を通して感じたのは、そういった場合は実際に関数や処理を実行してみせて値や実行結果がどう変化していくかを順番に確認していくことが有効でした。
口頭や文字で理屈を説明されるより、動いているものを見ながらの方が頭に入ってきやすいようです。

初心者の方に教える際は、上記を意識するといいのかなと思います。

Discussion