部分的には、関数式または関数宣言のどちらを使用しているかによって異なります。それらは異なるものであり、異なるタイミングで発生し、周囲のスコープに異なる影響を与えます。それでは、区別から始めましょう。
関数式はfunction
、結果を右側の値として使用するプロダクションです。たとえば、結果を変数またはプロパティに代入したり、パラメータとして関数に渡したりします。これらはすべて関数です。式:
setTimeout(function() { ... }, 1000);
var f = function() { ... };
var named = function bar() { ... };
(名前付き関数式と呼ばれる最後のものは使用しないでください。 実装にはバグがあり、特に IEがあります。)
対照的に、これは関数宣言です:
function bar() { ... }
それはスタンドアロンです。結果を右側の値として使用していません。
それらの間の2つの主な違い:
関数式は、プログラム フローで検出された場所で評価されます。宣言は、制御が含まれるスコープ (たとえば、含まれる関数またはグローバル スコープ) に入ったときに評価されます。
関数の名前 (ある場合) は、関数宣言の包含スコープで定義されます。関数式用ではありません(ブラウザーのバグを除く)。
あなたの無名関数は関数式であるため、インタープリターが最適化を行うことを禁止すると(これは自由に実行できます)、ループごとに再作成されます。したがって、実装が最適化されると思われる場合は使用しても問題ありませんが、名前付き関数に分割すると、他の利点があり、重要なことに、コストはかかりません。また、コードをどれだけ深く検査するかによって、インタープリターが各反復で関数の再作成を最適化できない理由についてのメモについては、カサブランカの回答を参照してください。
より大きな問題は、ループ、条件の本体などで関数宣言を使用した場合です。
function foo() {
for (i = 0; i < limit; ++i) {
function bar() { ... } // <== Don't do this
bar();
}
}
技術的には、仕様の文法をよく読むと、それを行うのは無効であることがわかりますが、実際にそれを強制する実装は事実上ありません。実装が行うことはさまざまであり、それを避けるのが最善です。
私のお金のために、あなたの最善の策は、次のように単一の関数宣言を使用することです:
function foo() {
for (i = 0; i < limit; ++i) {
bar();
}
function bar() {
/* ...do something, possibly using 'i'... */
}
}
同じ結果が得られます。実装がすべてのループで新しい関数を作成する可能性はありません。名前を持つ関数の利点が得られ、何も失うことはありません。