JavaScriptで関数を作成するには、「関数宣言」と「関数式」の2つの方法があります。「関数」が特定の行の最初の文字セットでない限り、関数式(宣言ではない)を実行していると彼が指摘したときに最もよく説明したのはダグ・クロックフォードだったと思います。
関数宣言は気難しい生き物です。あなたがそれらを見るとき、あなたはそれらを認識するでしょう。彼らはこのように見えます:
function foo() { /* ... */ }
それらには常に名前が付けられ(必要です)、その名前は、関数が宣言されている字句コンテキストにローカルでスコープされます。したがって、グローバルコンテキストで関数宣言を実行すると、その名前を介して関数をグローバルに参照できます。関数内で行う場合、関数の名前は、その関数内およびその関数内で宣言された関数内でのみ参照できます。
関数を宣言するこの方法(ほとんどコメントされないもの)の最も重要な側面は、関数の初期化が現在の字句コンテキストの先頭に引き上げられることだと思います。したがって、次のような条件内で関数宣言を使用しないでください。
//DON'T DO THIS!
if (x) {
function foo() { return 1; }
} else {
function foo() { return 2; }
}
foo(); //will always be 2, regardless of the value of x.
関数式は少し異なります。多くの場合、次のように、変数に直接割り当てられます。
var foo = function() { /* ... */ };
これは、初期化が引き上げられないことを除いて、上記の関数宣言とほぼ同じです。したがって、次のことができます。
var foo;
if (x) {
foo = function() { return 1; };
} else {
foo = function() { return 2; };
}
foo(); //will be 1 or 2, depending on the truthy-ness of x.
では、元の質問に戻りましょう。関数式にも名前を付けることができますが、名前は必須ではなく、関数が宣言されているコンテキストにスコープされていません(関数宣言の場合と同様)。代わりに、関数自体の字句コンテキストにスコープが設定されます。これは場合によっては非常に便利です。私の個人的なお気に入りはこのパターンです:
(function foo() {
//Do something.
setTimeout(foo, 1000);
}());
foo; //undefined
「関数」という単語の前に括弧があるため、これは関数式であり、名前は内部でのみスコープされます。しかし、それは問題ありません。内部的に(を介してsetTimeout()
)呼び出すだけでよいからです。その結果、関数はすぐに1回実行され、実行が終了した後、1秒ごとに再実行されます。setInterval()
これは、実行が完了するまで待機してから再スケジュールするため、使用するよりも安全です。これにより、実行の失敗やJavaScriptスレッドの「支配」を引き起こす可能性のある重複が防止されます。
基本的に、名前付き関数式の使用は制限されていますが、必要な場合は非常に強力です。