2016-11-30 1 views
5

これは昨日TC39で発表されました。この事がどのように動作するかjavacriptの範囲指定とクロージャの奇妙さ

var p =() => console.log(f); 
{ 
    p(); // undefined 
    console.log(f); // function f(){} 

    f = 1; 

    p(); // undefined 
    console.log(f); // 1 

    function f(){} 

    p(); // 1 
    console.log(f); // 1 

    f = 2; 

    p(); // 1 
    console.log(f); // 2 
} 

は、誰かが私に説明してもらえ:あなたは要点hereを見つけることができますか?記録のためにはは非厳密モードでのみ働いています

ありがとうございます。

+1

特にホスティングとの関係では?この回答は非常によく説明しています:http://stackoverflow.com/questions/25111087/why-is-a-function-declaration-within-a-condition-block-hoisted-to-function-scope – CodingIntrigue

+1

@CodingIntrigue:いいえ、これは、ES2015の附属書BとTC39の成果物であり、既存のコードと歴史的に一貫性のない実装の真っ逆さましい海域を操るために最善を尽くしたものです。 :-) –

+0

@ T.J.Crowderもっと詳しく説明してください。 'function f(){}'は通常通常の関数ブロックの中に持ち込まれ、最初の 'undefined'は関数f宣言を出力するはずですが、ブロック内で定義されているのはどうですか? – kstratis

答えて

2

私はすべての微妙なことを理解すると主張しませんが、これについての重要なことは、附属書Bの§B.3.3.1のほとんど奇妙な歪曲です。 f1ブロック(以下従ってlet)の字句環境へfの第2のコピー特定のコードは、これを効果的にしていることを

var p =() => console.log(f); 
{ 
    let f1 = function f(){};;   // Note hoisting 
    p(); // undefined 
    console.log(f1); // function f(){} 

    f1 = 1; 

    p(); // undefined 
    console.log(f1); // 1 

    var f = f1;       // !!! 

    p(); // 1 
    console.log(f1); // 1 

    f1 = 2; 

    p(); // 1 
    console.log(f1); // 2 
} 

そしてもちろん、var巻上げのおかげで、両方p

var f = undefined; 
var p = undefined; 
p =() => console.log(f); 
{ 
    let f1 = function f(){};;   // Note hoisting 
    p(); // undefined 
    console.log(f1); // function f(){} 

    f1 = 1; 

    p(); // undefined 
    console.log(f1); // 1 

    f = f1;        // !!! 

    p(); // 1 
    console.log(f1); // 1 

    f1 = 2; 

    p(); // 1 
    console.log(f1); // 2 
} 

キービットから:とfを効果的に初期値undefinedとコードスニペットの先頭に宣言されていますB.3.3.1は、内側の値f(上記ではf1と呼んでいます)を外側に転送します(Fは、文字列"f"、宣言されている関数の名前です)。

F FunctionDeclarationの が評価さ

3、14.1.21に設けFunctionDeclarationの評価アルゴリズムの代わりに、次の手順を実行し

fenvを実行コンテキストのVariableEnvironmentとします。

b。 fenvRecfenvのEnvironmentRecordになります。

c。 benvを実行コンテキストのLexicalEnvironmentとします。

d。 benvRecをbenv's EnvironmentRecordに差し上げましょう。

e。 がfobjになるようにしましょう! benvRec.GetBindingValue(F、false)。

f。実行! fenvRec.SetMutableBinding(F,fobj、false)。

g。 NormalCompletion(空)を返します。

変数環境が関数全体であるが、字句環境は(ブロック)は、より拘束されることを想起されたいです。

関数宣言を正規化しようとすると、{無効|不特定多数)、TC39は非常にです。過去の実装固有の動作に依存していた可能性のある既存のコードを破損しないように、動作を標準化しようとする危険なパスです(相互排他的です。 TC39はバランスを取ろうとしている)。

+0

最初の2つの 'p()'について少し詳しく説明できますか?なぜ彼らは「未定義」として出てくるのですか?そのビットが私を最も悩ませている。私たちはすでにホイストを持っているので、その時点で 'f'は既に定義されているはずです... – kstratis

+1

@kstratisはホイストが変数ではないことを覚えています。それは宣言を変更するだけなので、行10に 'var x = 5'と言うと、そのコードはファイルの先頭に' var x; '、行末に' x = 5' 10. 1〜9行目はまだ値が設定されていないので、 'x'は' undefined'と同じです。したがって、4行目で 'console.log(x)'を実行すると 'undefined'が生成されます。しかし、もしあなたが 'var x'を全く持っていなければReferenceErrorを生成します – vlaz

+1

@kstratis:上記のvlazのコメントを見てください。私は、それを明示的にするために2番目のコードスニペットを追加しました。 –

関連する問題