注:回答の最後にある更新を参照してください。ブロック内の宣言が有効になりました(ただし、厳密モードを使用していない場合は非常に複雑になります)。
これが1つの理由です:
var whatever;
if (some_condition) {
whatever = function() {
// Do something
};
}
else {
whatever = function() {
// Do something else
};
}
whatever();
ライブラリの初期化で、実装の違い(Webブラウザー間の違い、IEattachEvent
と標準の違いなど)を処理する必要があるようなコードが表示される場合がありますaddEventListener
。関数宣言で同等のことを行うことはできません。
if (some_condition) {
function whatever() { // <=== DON'T DO THIS
// Do something
}
}
else {
function whatever() { // <=== IT'S INVALID
// Do something else
}
}
whatever();
...これらは制御構造内で指定されていないため、JavaScriptエンジンは必要な処理を実行でき、エンジンが異なれば実行も異なります。(編集:繰り返しますが、以下の注を参照してください。これらは現在指定されています。)
これとは別に、
var whatever = function() {
// ...
};
と
function whatever() {
// ...
}
1つ目は関数式であり、コンテキストの段階的な実行(たとえば、含まれている関数、またはグローバルコードの段階的な実行)でコードがそのポイントに到達したときに評価されます。また、無名関数になります(それを参照する変数には名前がありますが、関数には名前がありません。これは、ツールが役立つことを意味します)。
2つ目は関数宣言であり、コンテキストに入ると、ステップバイステップのコードが実行される前に評価されます。(これを「巻き上げ」と呼ぶ人もいます。これは、ソースのさらに下の何かが、ソースの上の何かよりも早く発生するためです。)関数にも固有名が付けられています。
したがって、次のことを考慮してください。
function foo() {
doSomething();
doSomethingElse();
console.log("typeof bar = " + typeof bar); // Logs "function"
function bar() {
}
}
一方
function foo() {
doSomething();
doSomethingElse();
console.log("typeof bar = " + typeof bar); // Logs "undefined"
var bar = function() {
};
}
最初の例では、宣言を使用して、および他の段階的なコードが実行される前に宣言が処理されます。doSomething
2番目の例では、これは式であるため、段階的なコードの一部として実行され、関数は上で定義されていません(変数var
も「持ち上げられている」ため、上で定義されています)。
そして、まとめ:今のところ、一般的なクライアント側のWebではこれを行うことはできません。
var bar = function foo() { // <=== Don't do this in client-side code for now
// ...
};
これができるはずです。これは名前付き関数式と呼ばれ、関数に適切な名前を付ける関数式です。しかし、さまざまなJavaScriptエンジンがさまざまな時期にそれを誤解しており、IEはごく最近まで実際に非常に誤解を続けていました。
ES2015+のアップデート
ES2015(別名「ES6」)の時点で、ブロック内の関数宣言が仕様に追加されました。
厳密モード
厳密モードでは、新しく指定された動作は単純で理解しやすいものです。それらは、それらが発生するブロックにスコープされ、その上部に持ち上げられます。
したがって、この:
"use strict";
if (Math.random() < 0.5) {
foo();
function foo() {
console.log("low");
}
} else {
foo();
function foo() {
console.log("high");
}
}
console.log(typeof foo); // undefined
(関数の呼び出しがブロック内の関数の上にあることに注意してください。)
...基本的にこれと同等です:
"use strict";
if (Math.random() < 0.5) {
let foo = function() {
console.log("low");
};
foo();
} else {
let foo = function() {
console.log("high");
};
foo();
}
console.log(typeof foo); // undefined
ルーズモード
ルーズモードの動作ははるかに複雑であり、さらに理論的には、WebブラウザのJavaScriptエンジンとWebブラウザではないJavaScriptエンジンの間で異なります。ここでは入りません。ただそれをしないでください。ブロック内の関数宣言を主張する場合は、厳密モードを使用してください。厳密モードでは、それらが意味をなし、環境全体で一貫しています。