AFAIK関数foo(){aaa(); }は、JavaScriptではvar foo = function(){aaa()}です。
完全ではありません。それらは似ていますが、まったく異なります。JavaScriptには、2つの異なる、しかし関連するものがあります。関数宣言(最初の例)と関数式(2番目の例で変数に割り当てます)です。それらは解析サイクルのさまざまな時間に発生し、さまざまな効果があります。
これは関数宣言です:
function foo() {
// ...
}
関数宣言は、ステップバイステップのコードが実行される前に、囲んでいるスコープに入るときに処理されます。
これは関数式(具体的には匿名の式)です。
var foo = function() {
// ...
};
関数式は、(他の式と同じように)表示された時点でステップバイステップコードの一部として処理されます。
引用符で囲まれたコードは、次のような名前付き関数式を使用しています。
var x = function foo() {
// ...
};
:
(あなたの場合、それはオブジェクトリテラル内にあるので、の代わりに右側にありますが=
、それでも名前付き関数式です。)
これは完全に有効であり、実装のバグを無視します(後で詳しく説明します)。、という名前の関数を作成し、それをfoo
囲むスコープに入れずに、その関数を変数に割り当てます(これはすべて、ステップバイステップのコードで式が検出されたときに発生します)。私がそれが囲んでいるスコープに入れないと言うとき、私はまさにそれを意味します:foo
x
foo
var x = function foo() {
alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo); // alerts "undefined" (in compliant implementations)
これが関数宣言の動作(関数の名前が囲んでいるスコープに追加される)とどのように異なるかに注意してください。
名前付き関数式は、準拠した実装で機能します。歴史的に、実装にはバグがありました(初期のSafari、IE8以前)。IE9以降を含む最新の実装はそれらを正しくします。(詳細はこちら:ダブルテイクとこちら:名前付き関数の式はわかりやすく説明されています。)
したがって、この例では、me
変数shoudlはメソッド内から正しく解決されません。
実際にはそうあるべきです。関数の実際の名前(との間の記号function
と開き括弧)は、関数内で常に範囲内にあります(関数が宣言からのものであるか、名前付き関数式からのものであるかは関係ありません)。
注:以下は2011年に作成されました。それ以降のJavaScriptの進歩により、IE8(最近は非常にまれです)を扱う予定であることがわからない限り、以下のようなことを行う必要はなくなりました。
実装のバグのため、私は名前付き関数式を避けていました。あなたの例ではme
名前を削除するだけでそれを行うことができますが、私は名前付き関数を好むので、その価値のために、私があなたのオブジェクトを書いた方法は次のとおりです。
var foo = (function(){
var publicSymbols = {};
publicSymbols.bar1 = bar1_me;
function bar1_me() {
var index = 1;
alert(bar1_me);
}
publicSymbols.bar2 = bar2_me;
function bar2_me() {
var index = 2;
alert(bar2_me);
}
return publicSymbols;
})();
(私がおそらくより短い名前を使用することを除いてpublicSymbols
。)
処理方法は次のとおりです。
- ステップバイステップのコードで行が検出されると、匿名の囲み関数が作成され
var foo = ...
、それが呼び出されます(()
最後にがあるため)。
- その無名関数によって作成された実行コンテキストに入ると、
bar1_me
およびbar2_me
関数の宣言が処理され、それらのシンボルがその無名関数内のスコープに追加されます(技術的には実行コンテキストの変数オブジェクトに追加されます)。
- シンボルは無名関数内の
publicSymbols
スコープに追加されます。(詳細:誤解が少ないvar
)
- ステップバイステップのコードは、に割り当てること
{}
から始まりますpublicSymbols
。
- ステップバイステップのコードは、
publicSymbols.bar1 = bar1_me;
とpublicSymbols.bar2 = bar2_me;
、そして最後に続きますreturn publicSymbols;
- 匿名関数の結果はに割り当てられ
foo
ます。
ただし、最近では、IE8をサポートする必要があることがわかっているコードを記述していない限り(残念ながら、2015年11月にこれを記述しているため、依然としてかなりの世界市場シェアを持っていますが、幸いにもそのシェアは急落しています)、心配する必要はありません。 。最新のJavaScriptエンジンはすべて、それらを正しく理解しています。
次のように書くこともできます。
var foo = (function(){
return {
bar1: bar1_me,
bar2: bar2_me
};
function bar1_me() {
var index = 1;
alert(bar1_me);
}
function bar2_me() {
var index = 2;
alert(bar2_me);
}
})();
...これらは関数宣言であるため、引き上げられます。宣言とプロパティへの割り当てを並べて行うと(IE8の場合は同じ行で)、大きな構造のメンテナンスが簡単になるため、通常はそのようにはしません。 。