JavaScriptにおける通常の関数とアロー関数の違い、いつどの構文を使うべきか
(jrsinclair.com)- JavaScriptの関数宣言には、
functionキーワードを使った宣言、関数式、アロー関数などさまざまな方法がある - 関数宣言には ホイスティング が適用されるため、コード内のどの位置からでも参照できる
- Arrow(アロー)関数は 簡潔な構文 が利点だが、this/arguments/super のバインディングがない など重要な違いがある
- コンストラクタ関数、ジェネレーター、メソッド にはアロー関数の使用は適していない
- 単純なコールバックや無名関数 には アロー関数 のほうが適している
Function Declarations, Function Expressions, and Arrow Functions
- JavaScriptでは、関数宣言(Statement)、関数式(Expression)、アロー関数(Arrow Function) の3つの方法で関数を定義できる
- 関数宣言は
function isVowel(chr) { ... }のように名前を直接バインドし、コードのどこからでも参照可能(ホイスティング)。スタックトレース や デバッグ の際にも関数名が明確に表示される - 関数式は
const takeWhile = function(predicate, arr) { ... }のように、変数に無名関数を代入する形 - 関数式にも内部的に名前を付けられるが、その名前は外側のスコープにはバインドされず、主に スタックトレースでのエラー追跡に使われる
Hoisting and Naming
- 関数宣言文 はJavaScriptエンジンによって ホイスティング されるため、宣言前に呼び出しても動作する
- 無名の関数式は、変数への代入後にのみ呼び出し可能
- デバッグのために関数へ 明示的に名前を付ける ことは、スタックトレース上で有利になる場合がある
Arrow Functions
- 短く簡潔な構文:
functionキーワードなしで(引数) => { ... }の形で書く - 常に無名関数 である(ただし、変数に代入して名前のように使うことは可能)
- 式(expression)としてのみ使え、文(statement)ではない
- this/arguments/super のバインディングがない: 関数宣言・関数式とは異なり、外側のスコープの this をキャプチャする
- 単一の式であれば波かっこと
returnを省略でき、引数が1つならかっこも省略できる - コンストラクタとして使えない: アロー関数は new キーワードで呼び出せず、コンストラクタ関数として動作しない
- ジェネレーターにできない: yield は使えず、ジェネレーター関数にはできない
- コード例:
const sum = (a, b) => a + b; const square = x => x * x;
Practical Example: thisとコンストラクタ、ジェネレーター
- 通常の関数とアロー関数での this の扱いの違いを示す例を紹介
- オブジェクト内でメソッドとして使う場合、通常の関数では this はオブジェクト自身を指すが、アロー関数では undefined または外側のスコープの this を指す
- コンストラクタ関数をアロー関数で定義すると TypeError が発生する
- ジェネレーター関数は必ず
function*構文を使う必要がある
どの関数構文をいつ選ぶべきか?
- ジェネレーター(yield を使用) が必要 →
function*を使う - this を活用 する必要がある →
functionキーワードまたはクラスメソッドを使う - ホイスティング が必要、または上位レベルでの可読性を重視したい → 関数宣言文を使う
- 上記に当てはまらないなら → アロー関数 でより簡潔に書くのが有利
結論
- JavaScriptの関数は、用途、this の必要性、コンストラクタ/ジェネレーターかどうかによって構文を選ぶ
- 日常的なコールバック/単純な関数 には アロー関数 が最適
- オブジェクトメソッド/コンストラクタ/ジェネレーター には
function構文が必要 - ホイスティング や宣言順序の自由度が必要なら、関数宣言文が有利
3件のコメント
根本的な点と同じくらい、
prototypeの有無も ...生成される高階関数のリファレンス方法も ...
const a = (a: () => null): (() => () => null) =>() => a
() => ❤️