本記事は、Mahdhi Rezvi氏による「36 JavaScript Concepts You Need to Master to Become an Expert」(2020年7月20日公開)の和訳を、著者の許可を得て掲載しているものです。
#JavaScriptエキスパートになるための36の概念
習得には時間がかかる。でも何をすべきか分かれば簡単になる。
Photo by Angela Compagnone on Unsplash
##はじめに
「JavaScriptはヘンで、時に無価値だ」という不満を多くの人が耳にするでしょう。このような文句が出るのは、それが内部でどのように動作するかを理解していないからです。JavaScriptのシナリオのいくつかが異なる方法で処理されていることには同意します。でもだからと言って、それがヘンなものになるわけではなく、むしろそれ自体が素晴らしいのです。
あるプログラミング言語を好きになるには、まずその奥深くに目を向け、概念を一つ一つ習得していくことから始めましょう。
ここでは、総合的なJavaScriptエキスパートになるために習得すべき36の概念を紹介します。
これは私の記事の中では最も長い部類ですが、読む価値があることを保証します。リソースを提供してくれたStephenとLeonardoに称賛を送ります。
リソースとして、ここで説明する概念の全ての学習教材があるLeonardoのGitHubリポジトリリンクを掲載しています。さあ、概念の解説に入りましょう。
##1. コールスタック実行
Stack Overflowというサイトは皆さんも聞いたことがあるでしょう。でも、実際のスタックオーバーフローを知っていますか?コールスタックの操作に関連したエラーのことです。
コールスタックを理解することで、JavaScriptのような高水準言語の実行方法について、実務的な知識を持つことができます。
##2. プリミティブデータ型
const foo = "bar";
foo.length; // 3
foo === "bar"; // true
待って!
定数foo
に値bar
を代入すると、プリミティブ型のstring
になります。これは大丈夫ですよね?でも、プリミティブ型文字列のlength
プロパティにはどのようにアクセスするのでしょうか?
何かヘンだと思いますか?いいえ。
これは「オートボクシング」という機能です。先の例は、JavaScriptは定数を一時的なラッパーオブジェクトでラップし、そのオブジェクトのlengthプロパティにアクセスしています。このステップが完了すると、オブジェクトは安全に破棄されます。
プリミティブ型について深い知識を持つことで、それがどのようにメモリに格納されているかをバイナリ表現の時点まで知ることができます。また、これらの「ヘンな」状況がどのように発生するのか、その背後にある論理的な理由を知ることができます。
##3. 基本型と参照型
最近、JavaScriptでの「参照渡し」がどのように動作するのか分からないことがありました。C言語やJavaでの「参照渡し」や「値渡し」は分かっていたものの、JavaScriptでは確信が持てなかったのです。
JavaScriptで非プリミティブ値に代入した変数には、その値への参照が代入されることを知っていますか?値が格納されているメモリの位置を参照しています。
var arr1 = [1,2,3];
var arr2 = arr1;
arr2.push(10);
console.log(arr2);
//[1, 2, 3, 10]
console.log(arr1);
//[1, 2, 3, 10]
例から分かるように、arr2
に加えた変更はarr1
にも反映されます。これは、実際の値そのものではなく、値への参照だけを保持しているからです。
基本型と参照型の概念を理解することで、変数に値やメモリ参照が代入される方法を理解できるようになります。
##4. 型変換
ここでは主に、暗黙的型変換と明示的型変換の違いについて説明します。これはJavaScriptの中でよく間違えられる数少ない分野です。特に、暗黙的型変換で当てはまります。データ型によって挙動が異なるからです。
これは、面接でよく聞かれるJavaScriptの分野です。
Number('789') // explicit
+'789' // implicit
789 != '456' // implicit
9 > '5' // implicit
10/null // implicit
true | 0 // implicit
型変換はJavaScriptの最もトリッキーな概念の1つなので、これを理解できれば喜んで良いと思います。
##5. 等価演算子とtypeof演算子
ここでは基本的に、二重等式==と三重等式===の使用方法、場面と理由を説明します。表面的には同じように見え、ほとんどの場合は同じ結果が得られますが、無意識で使用していると予期せぬバグが発生することがあります。
また、typeof
演算子を使用し、出力の可能性を知る必要があります。オブジェクトが出てくると混乱することがあります。
typeof 3 // "number"
typeof "abc" // "string"
typeof {} // "object"
typeof true // "boolean"
typeof undefined // "undefined"
typeof function(){} // "function"
typeof [] // "object"
typeof null // "object"
##6. JavaScriptスコープ
スコープは、JavaScriptの旅の最初に完成させるべき概念の1つだと思います。[Wissam] (https://www.telerik.com/blogs/author/wissam-abirached)によれば、スコープを簡単に定義すると、コンパイラが必要な時に変数や関数を探す場所です。
スコープを理解することで、JavaScriptをより効率的かつ効果的に使用できるようになります。グローバルスコープと、レキシカルスコープとしても知られるブロックスコープと関数スコープについて学習する必要があります。JavaScriptスコープは、最初はかなりややこしく見えますが、内部での動作を理解すると、使うのがとても楽しくなるでしょう。
##7. 文と式
文と式はJavaScriptの2大構文カテゴリです。2つの違いと文の評価方法を知る必要があります。これにより、コードがどのような式と文の構造になっているかを、全体的に理解することができるようになります。コードのほとんどが式であるのに対し、文の数は比較的少ないことに気付くでしょう。また、この2つを不適切に使用した結果として、発生するバグを回避することができるようになります。
##8. 即時呼び出し関数式(IIFE)とモジュール
即時呼び出し関数式(IIFE)は、定義されるとすぐに実行される関数です。グローバルスコープの汚染を回避するために、主に使われます。後にES6モジュールの導入で、グローバルスコープの汚染を回避する標準的な方法が提供されました。ただし、IIFEの直接の代替ではないと考える人もいます。
IIFEとモジュールを理解することで、グローバル空間の誤った処理に起因するバグの少ないアプリケーションを構築できます。ただ、モジュールの使用では、かなり多くのことができます。
##9. メッセージキューとイベントループ
MDNのドキュメントに記載の通り、JavaScriptにはイベントループに基づく、並行処理モデルがあります。イベントループはコードの実行、イベントの収集と処理、キューに入れたサブタスクの実行を行います。このモデルはCやJavaなどの他の言語のモデルとはかなり異なります。
この並行処理モデルでは、メッセージキューを使用して、古いものから順にメッセージを処理します。イベントリスナーを追加したイベントが発生した場合、常にメッセージが追加されます。
この概念を理解することで、JavaScript内部での動作とコード解釈をよりよく理解できます。
##10. 時間間隔
JavaScriptで呼び出しや関数をスケジュールするには、2つのメソッドがあります。
-
setTimeout
は、特定の時間間隔の後に関数を1回実行します。 -
setInterval
は、特定の時間間隔の後に開始し、その間隔で継続的に繰り返す関数を実行します。
これは、先のメッセージキューとイベントハンドラーの概念と多少関連があります。そのため、時間間隔のメソッドを理解することで、その動作を理解し、効率的に事例で使用できます。
##11. JavaScriptエンジン
私達は今、JavaScriptについて深く掘り下げているところです。JavaScriptエンジンは、JavaScriptコードを実行するコンピュータプログラムまたはインタープリタです。JavaScriptエンジンは、さまざまな言語で記述できます。例えば、Chromeブラウザで使用されているV8エンジンはC++で、Firefoxブラウザで使用されているSpiderMonkeyエンジンはCとC++で記述されていました。
効率的なコード記述には、どのJavaScriptエンジンで作業しているかを理解することが不可欠です。Webビューを使用するモバイル開発者は、これに特に注意する必要があります。
##12. ビット演算
ビット演算は、値を10進数、16進数、8進数ではなく、ビット(0と1)として扱います。
ビット演算子はこのようなバイナリ表現に対して演算を行いますが、JavaScriptの標準的な数値を返します。
通常、この演算をコードで使用することはありませんが、事例はあります。偶数値と奇数値、色変換、色抽出、設定フラグを見つけるために使用できます。
ビット演算を完全に理解することで、ピクセル操作を多く含むWebGLのような技術を、十分に扱うことができます。
##13. DOMツリーとレイアウトツリー
ドキュメントオブジェクトモデル(DOM)について聞いたことがあると思いますが、深く知っている人はごくわずかです。ブラウザに表示されるものがDOMではないことを知っていますか?それはむしろレンダリングツリーであり、実はDOMとCSSOMの組み合わせです。
DOMの動作、構造化、ページレンダリングの方法を理解することで、JavaScriptを使用してWebページを動的に操作できます。これは特に、アプリケーションのパフォーマンスの高さを確認するのに必要です。
##14. クラスとファクトリ
JavaScriptはオブジェクト指向言語ではありませんが、OOPのプロパティを模倣するために、コンストラクタ関数が導入されました。Taniaによると、「JavaScriptのクラスは実際には追加機能はなく、よりクリーンで美しい構文になるという点で、しばしばプロトタイプや継承よりも「シンタックスシュガー(糖衣構文)」があるものとして説明されます。
他のプログラミング言語はクラスを使用しているため、JavaScriptのクラス構文により、開発者は言語間をより容易に移動できます。」
ファクトリ関数はオブジェクトを返す関数で、クラスやコンストラクタ関数ではありません。JavaScriptの第一人者Eric Elliotは「JavaScriptでは、どの関数でも新しいオブジェクトを返すことができます。コンストラクタ関数やクラスでない場合、ファクトリ関数と呼ばれます。」と述べています。
特に、大容量・大規模アプリケーション開発を始める場合は、この2つの概念を十分に理解する必要があります。
##15. thisキーワードとapply/call/bindメソッド
this
キーワードを理解することがJavaScript開発者には極めて重要なことである、と個人的には思っています。
正しく理解しないと、後々アプリケーションでさまざまな問題が発生します。
this
キーワードをよく理解すれば、apply
/call
/bind
メソッドに集中できます。このメソッドは、適切なコンテキストで関数を呼び出すために必要です。this
にアクセスするコールバックを渡す時に、特にbind
メソッドが必要になります。
私は友人のコードのデバッグを手伝った時にこれを学びました!
##16. コンストラクタ関数とinstanceOf演算子
コンストラクタ関数は通常の関数と同じですが、相当な違いがあります。慣例により、関数名は大文字で始まり、new
演算子でしか実行できません。new
キーワードは、OOPの経験者であるプログラマには馴染みがあるでしょう。
オブジェクトの型を適切に識別するために、instanceOf
演算子を使用します。簡単に言うと、オブジェクトが別のオブジェクトのインスタンスであるかどうかをチェックするものです。
これにより、オブジェクトが他のオブジェクトから継承する方法を理解できます。継承は「プロトタイプ」によって実現されます。
##17. プロトタイプ
これは、10年の経験がある人でも、JavaScriptで最も混乱しやすい概念の1つです。
JavaScriptのプロトタイプは、オブジェクト間で共通の機能を共有するための仕組みです。
JavaScriptのほぼ全てのオブジェクトはObject
のインスタンスです。一般的なオブジェクトは、Object.prototype
から全てのプロパティとメソッドを継承します。
簡単に言うと、プロトタイプとは、JavaScriptオブジェクトがメソッドとプロパティを継承する元となるオブジェクトです。
プロトタイプをよりよく理解することで、効率的で高速なアプリケーションを構築できます。
##18. new/Object.create/Object.assignを使用したオブジェクトの作成
JavaScriptのオブジェクト作成方法は数多くあります。しかし、new
キーワードではなくObject.create
メソッドを選択するのには理由があります。Object.create
メソッドを使用すると、既存オブジェクトを新規オブジェクトのプロトタイプとして使用できます。これにより、OOPの継承の概念のように、既存オブジェクトのプロパティと関数を再利用できます。
Object.assign
メソッドを使用すると、1つ以上の「ソースオブジェクト」から「ターゲットオブジェクト」に、列挙可能な自身のプロパティをコピーできます。この場合、ターゲットオブジェクトのプロトタイプには、ソースオブジェクトのプロパティは含まれません。これが、この2つのメソッドの主な違いです。
この3つのオブジェクト作成方法を理解することで、事例に応じ、アプリケーション内で適切に使用してメモリ効率の高いプログラムを作成できます。
##19. map/filter/reduceメソッド
arrayプロトタイプのこの3つのメソッドは、配列操作に非常に役立ちます。
map
メソッドは、配列の全要素に対して/要素で何かを実行したい場合に使用します。
filter
メソッドは、配列の全要素で条件を実行し、条件に一致する値を取得する場合に使用します。
reduce
メソッドは、配列の全要素に対して関数を実行し、最後に1つの値を返します。配列の全要素の合計を求めるものが好例です。
let numbers = [1,2,3,4,5,6]
const reduced = numbers.reduce( (accumulator, currentValue) => accumulator + currentValue )
console.log(reduced)
// 21
この3つのメソッドが、元の配列の値を変化・変更しないことに注意してください。
##20. 純粋関数、副作用と状態変化
この3つの概念は、JavaScript開発者にとって非常に重要です。状態変化は、React開発者にとって特に重要です。
純粋関数は、スコープ外の変数にアクセスも変更もせず、同じ入力値に対して常に同じ戻り値を返す関数です。この種の関数は、読み込み、デバッグ、テストが容易です。
副作用は、必要のない時に、変数が作成されスコープ全体で使用できるようにするコードの一部です。関数がスコープ外の変数にアクセスしている場合、副作用があります。
状態変化は、変数の値を変更することです。変数の変更により、変更前の値によっては他の関数に影響を与える可能性があります。React環境では、状態を変化させないことをお勧めします。これはReactの不変性に関する良い読み物です。
##21. クロージャ
クロージャは理解するのが難しい概念ですが、一度理解するとJavaScriptの素晴らしさが見えてきます。オンラインには豊富なリソースがあります。クロージャを学ぶのに時間を取るようにしてください。
クロージャは、スコープ内で関数スコープ外にアクセスできます。関数が作成される時に、その都度JavaScriptクロージャが作成されます。
クロージャを使用すべき理由を知ることで、クロージャへの理解を深められます。
##22. 高階関数
高階関数は、他の関数を引数として渡したり、戻り値として返したりする関数です。高階関数により「合成」は最大限の力を発揮します。1つのタスクだけ処理する小さな関数を作成し、それを使用して複雑な関数を作成できます。その結果、コードの再利用性も向上します。
また、バグが減り、コードが読みやすく理解しやすくなります。
##23. 再帰
再帰は、全プログラミング言語に共通の概念です。簡単に言うと、大きな問題を小さく分割してから、小さな問題を解決するという概念です。
実際には、自分自身を呼び出す関数を記述することです。再帰の概念は理解するのが難しいかもしれませんが、小さな問題から始めて多くの練習を積むことで、より良く理解できるようになります。
しかし、再帰に気を付けないと、スタックオーバーフローエラーが発生する可能性があるので、注意してください。演習として、このエラーについて調べてみてください。このエラーのコンテキストを完全に理解するには、記事冒頭のコールスタックに関する知識を見直す必要があります。
##24. コレクションとジェネレータ
コレクションとジェネレータは、ES6で新たに導入されました。新しく導入されたコレクションは、Map
、Set
、WeakSet
、WeakMap
です。コレクションには、活用できる非常に優れた事例があります。特に最新のJavaScriptでは、これに関する知識が不可欠です。
一方、ジェネレータは、特に初心者の皆さんにとって、理解するのが少し難しい場合があります。ジェネレータにより、他のコードの実行をブロックせずに、関数の一時停止や再開の機能のあるコード関数を記述できます。これは、JavaScriptでは非常に珍しいことです。
##25. Promise
JecelynはPromiseをこう説明しています。「あなたが子供だと想像してみてください。あなたのお母さんは、来週あなたに新しい電話をくれると約束しています。」
その電話が手に入るかどうかは、来週まで分かりません。お母さんが本当に新しい電話を買ってくれるのか、それとも機嫌が悪くて買ってくれないのか、どちらかです。
これがPromiseです。Promiseには次の3つの状態があります。
-
保留。あなたが電話を手に入れるかどうか分かりません。
-
履行。お母さんは機嫌が良く、あなたに電話を買ってくれます。
-
拒否。お母さんは機嫌が悪く、あなたに電話を買ってくれません。
これは私が見た中で、最も単純明快なPromiseの説明です。正直に言うと、私はデモプロジェクトに取り組みながら、Promiseの概念を学びました。Promiseが何かを全く知らなかったので、何が起こっているか理解するのは本当に困難でした。現在まで早送りします。オンラインの豊富なリソースのお陰で、Promiseへの理解が深まりました。プロジェクトの実務知識と相まって、明確に理解できるようになりました。
##26. 非同期プログラミング
非同期プログラミングとは何かを理解するために、まず同期プログラミングの知識を新しくしましょう。同期プログラミングはスレッドブロッキングであり、JavaScriptはシングルスレッドのため、コードは1行ずつ実行されます。
しかし非同期プログラミングでは、メインスレッドをブロックせず長いネットワーク要求を実行できます。これは特に、完了まで長い時間を要する複数タスクの実行が必要な場合に便利です。ただし長いタスクでも、スレッドのブロックが必要な場合があります。その場合、async/await
の概念を使用します。
この概念をしっかり学ぶことで、実行中のタスクが多い場合でも効率的に動作するプログラムを記述できるようになります。
##27. ES6矢印関数
矢印関数はES6で導入された、通常の関数を構文上置き換えるものです。違いは、矢印関数がthis、arguments、super、new.targetキーワードにバインドされないことです。これにより、矢印関数はあるシナリオでは素晴らしい選択に、あるシナリオでは非常に悪い選択になります。
そのため矢印関数を常に使用する習慣をつけてはいけません。事例に応じて実装してください。
##28. データ構造
データ構造は、プログラミング言語に関係なく、開発者が持つべき必須知識の1つです。
「悪いプログラマはコードを心配し、良いプログラマはデータ構造とその関係を心配する。」
LinuxとGitの生みの親 Linus Torvalds
さまざまなデータ構造に関する深い知識を持つことで、さまざまな状況下で適切に動作する効率的なプログラムを構築できます。リンクリスト、キュー、スタック、ツリー、グラフ、ハッシュテーブルについて知っておく必要があります。
##29. 時間の複雑さ
時間の複雑さの分析も、プログラミング言語に関係なく、コンピュータプログラミングの基本の1つです。より良いアプリケーションの構築には、より良い解決策の作成が必要です。そのためには時間の複雑さの概念を理解する必要があります。「Big O」と呼ばれることもあります。
Big O表記は、アルゴリズムが必要とする実行時間やスペースを表します。Big
Oとは、最悪のシナリオの場合のことも指します。
そのため、最悪のシナリオでも最高のパフォーマンスを発揮するアルゴリズムを選択して実装できます。
##30. アルゴリズム
アルゴリズムは、コンピュータサイエンスのコースで最初に教わることの1つです。簡単に言うと、何かを達成するための段階的プロセスのことです。プログラマは、どのような問題もアルゴリズムの観点から見ることができなければなりません。問題とその解決策を、段階的プロセスで構成する必要があります。アルゴリズムは、後でプログラムとして記述するものです。
何千もの事例に応じて数多くのアルゴリズムが存在しますが、その中の2つは非常に普及しています。
-
サーチ
-
ソート
この2つはプログラマには周知のもので、少なくとも、良く知られた利用可能なアルゴリズムについては十分な知識を持っている必要があります。どのアルゴリズムを使用すべきか決まったルールはありませんが、このアルゴリズムはパフォーマンスの点でも有名で、十分に裏付けがあります。
独自のアルゴリズムを作成して世界に紹介することもできます。もし、現在知られているアルゴリズムよりも優れていれば、あなたは次のプログラミングスターになれるかもしれません!
##31. 継承とポリモーフィズム、コードの再利用
JavaScriptの継承は、プロトタイプで動作します。これはJavaScriptが非OOP言語であるためですが、JavaScriptはプロトタイプの継承により、OOPのいくつかの機能を提供しています。
一方、ポリモーフィズムは、オブジェクト、変数、関数が複数の形式をとれる概念です。JavaScriptでは、ポリモーフィズムの効果を確認するのは少し難しくなります。静的型システムにおいては、従来の型のポリモーフィズムの方が、効果がより顕著になるためです。
2つの概念はどちらも、JavaScriptでのコードの再利用に役立ちます。特にJavaScriptでは、これをしっかり理解することで、非常に高品質で実用的なコードを記述できます。
##32. デザインパターン
ソフトウェアエンジニアリングでは、デザインパターンは、一般的に発生する問題に対する再現可能な周知の解決策のことです。デザインパターンはいくつかあり、それぞれ独自の事例があります。23 Gang of Four(GoF)パターンは、一般的に他の全てのパターンの基礎と考えられています。全てを知ることはかなり難しいですが、少なくとも事例を理解しようとすることはできます。
これは、23 GoFパターンをJavaScriptで実装したFelipe の素晴らしいリポジトリです。記事の最後に記載しているリソースに目を通し、この記事のインスピレーションの源であるLeonardoの素晴らしいリソースに親しんでください。
##33. 関数型プログラミング
Wikipediaによれば、「関数型プログラミングとはプログラミングパラダイム、つまりコンピュータプログラムの構造と要素の構文スタイルのことであり、計算を数学関数の評価として扱い、状態や可変データの変更を回避するものです。」
関数型プログラミングには、習得すべき概念がいくつかあります。
- 純粋関数
- 不変性
- 参照透過性
- 高階関数
関数型プログラミングのこの概念を理解することで、間違いなくあなたは優位になります。
##34. クリーンコードの原則
これはプログラミング言語に関係なく、全ての開発者が習得すべき重要なスキルです。各プログラミング言語には、それぞれにクリーンコードの原則があります。「良い」方法とは主観的なもので、職場により異なりますが、一般的に「良い」と認められた方法がいくつかあります。
コード原則に従うことで、誰にとっても可読性と保守性のあるコードが記述でき、アプリケーション開発中にあなたとチームがスムーズに連携できるようになります。
##35. 分割代入
分割代入演算子はES6で導入されました。相当数の事例があり、間違いなく知っておくべき概念です。これは同じ事例の先の実装より簡単で効率的です。スプレッド演算子としても知られています。
分割代入については、私の記事で詳しく説明しています。
##36. ES2020の新機能
継続的な学習なくしてプログラミング言語のエキスパートにはなることはできません。これは、プログラミングの素晴らしさの1つです。プログラミング言語は、メジャーリリースの度に追加機能が導入され、時間と共に進化し続けています。
それは、概念に関する専門知識が10年後には時代遅れか非推奨になることを意味します。より良い代替手段がバージョンアップでリリースされるためで、どのプログラミング言語でも良くあることです。
ES2020では、オプショナルチェイニング、Null合体、動的importなど、いくつかの新機能がリリースされました。急速に変化するITの世界についていくためには、新しい概念を学ぶことが不可欠です。新機能については、このブログ投稿で確認できます。
##まとめ
言語の習得には何年もの経験と時間を要しますが、何を習得すべきか知ることで、習得が容易になります。
次のリソースを、36の概念の学習教材にしてください。このGitHubリポジトリから始めるのが良いでしょう。
お読み頂きありがとうございました!楽しいコーディングを!
##リソース
[Stephen Curtisの記事] (https://medium.com/@stephenthecurt/33-fundamentals-every-javascript-developer-should-know-13dd720a90d1)
Leonardo MaldonadoのGitHubリポジトリ
Zack Shapiroに謝意を表します。
##翻訳協力
Original Author: Mahdhi Rezvi
Original Article: 36 JavaScript Concepts You Need to Master to Become an Expert
Thank you for letting us share your knowledge!
この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。
選定担当: @gracen
翻訳担当: @gracen
監査担当: -
公開担当: @gracen
##ご意見・ご感想をお待ちしております
今回の記事は、いかがだったでしょうか?
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に
コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
皆様のメッセージをお待ちしております。