最近、名前付き関数式 (NFE) に関する興味深い事実に出くわしました。関数本体内で NFE の関数名にアクセスできることを理解しています。これにより、再帰がより便利になり、節約できarguments.callee
ます。また、関数名は関数本体の外では使用できません。例えば、
var foo = function bar() {
console.log(typeof bar);
};
typeof foo; // 'function'
typeof bar; // 'undefined', inaccessible outside the NFE
foo(); // 'function', accessible inside the NFE
これは十分に文書化された機能であり、kangax は NFE に関する素晴らしい投稿をしており、そこでこの現象について言及しています。私が最も驚いたのは、NFE の関数名を関数本体の他の値と再関連付けできないことです。例えば、
(function foo() {
foo = 5;
alert(foo);
})(); // will alert function code instead of 5
foo
上記の例では、識別子を別の値で再バインドしようとしました5
。しかし、これは失敗します!そして、ES5 仕様に目を向けると、NFE の作成時に不変のバインディング レコードが作成され、レキシカル環境の環境レコードに追加されていることがわかりました。
問題は、NFE が関数本体内で独自の関数名を参照するときに、名前が自由変数として解決されることです。上記の例でfoo
は、 は NFE 内で参照されていますが、この関数の仮パラメーターでもローカル変数でもありません。したがって、これは自由変数であり、そのバインド レコードは NFE の [[scope]] プロパティを通じて解決できます。
したがって、これを考慮してください。外側のスコープに同じ名前の別の識別子がある場合、競合が発生しているようです。例えば、
var foo = 1;
(function foo() {
alert(foo);
})(); // will alert function code rather than 1
alert(foo); // 1
NFE を実行すると、自由変数 foo
は関連付けられている関数に解決されました。しかし、コントロールが NFE コンテキストを終了するfoo
と、外側のスコープでローカル変数として解決されました。
だから私の質問は次のとおりです。
- 関数名の不変バインディング レコードはどこに保存されますか?
foo
NFEvar foo = 1
内で解決されると、関数名が優先されるのはなぜですか? それらの結合レコードは同じ字句環境に保管されていますか? もしそうなら、どのように?foo
関数名は内部ではアクセスできるが、外部では見えないという現象の背後にあるものは何ですか?
誰かがES5仕様でこれに光を当てることができますか? オンラインでの議論はあまり見当たりません。