2016-05-17 12 views
2

誰かが、以下の2つのコードスニペットが異なる結果を印刷する理由を説明できますか?ホイストと可変スコープ

違いは条件文の中にあります。最初は、名前に「Jack」というローカル変数が割り当てられています。条件はtrueyです(nameはtrueに評価されます)。 2つ目は、同じ名前の 'Jack'がグローバル変数名に割り当てられますが、条件はfalsyです(!nameはfalseです)。私の質問は、他のすべてが同じである場合、なぜ変更されたものがの中にある場合、最初の条件が真で2番目が偽であるのですか?条件付きのボディ?

私の唯一の説明は、それが最終的にnameは、変数の宣言を掲揚する必要があるかどうかにかかわらず、ローカル/グローバルであるかどうかを判断し、どのようにしている、条件付きの本体はJSインタプリタ最初によって読み取られていることです異なる名前の値が記録されます。

本体の解釈を開始する前に条件付き論理値を最初に評価してはいけませんか?両方の場合、変数 'name'は 'undefined'と評価されます...どんな助けでも大歓迎です!

ホイスト/スコープのコンテキストについては、本当に良いリソースがいくつかありますが、この質問に具体的に答えるものは見つかりません。あなたがvarを使用する場合

http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/

var name = "Paul"; 
function users() { 
    if (!name) { 
     var name = "Jack"; //<== difference is here, *inside* conditional body 
    } 
    console.log(name); 
} 
users(); //outputs "Jack" 

var name = "Paul"; 
function users() { 
    if (!name) { 
     name = "Jack"; //<== difference is here, *inside* conditional body 
    } 
    console.log(name); 
} 
users(); //outputs "Paul" 
+1

あるケースでは、ローカル変数があり、もう一方にはローカル変数がありません。なぜ結果は同じでしょうか? – Bergi

+0

@Bergiホイスト変数宣言が条件付きのロジックを変更しなかった場合、戻り値は同じになります。 –

+0

* "どちらの場合でも変数 'name'は 'undefined'として評価されるべきではありません" * Uh no? 2番目の例では、 'name'はローカル変数ではありません。これは '' Paul "'という値を持つグローバル変数を参照します。ホイストは変数宣言にのみ適用されます。 2番目の例の関数内には変数宣言はありません。 –

答えて

4

変数の宣言は、実行の先頭に掲げコンテキスト、この場合は関数ユーザーです。それが掲揚視点からどのように見えるかを示すために、これらの書き換えがしばしば混乱をクリア

var name = "Paul"; 
function users() { 
    var name;//<- hoisted variable declaration 
    if (!name) { 
     name = "Jack"; 
    } 
    console.log(name); 
} 
users(); //outputs "Jack" 

var name = "Paul"; 
function users() { 
    if (!name) {//no hoisted variable declaration, uses global 
     name = "Jack"; 
    } 
    console.log(name); 
} 
users(); //outputs "Paul" 

実行コンテキストは、いくつかの主要コンポーネントが含まれ、ここで最も関連がレキシカル環境変数環境です。あなたがここに興味を持っているなら、私は2つの(そしていくつかの短い歴史)の違いをカバーします:https://stackoverflow.com/a/32573386/1026459

+0

を編集し、 'var name =" Paul "; function users(){ name = "Dietrich"; if(!name){ var name = "Jack"; } console.log(name); } users(); // "Dietrich"を出力します。 :) –

+0

@BekimBacaj - 名前は "Dietrich"で上書きされました!名前のチェックは偽で入力せず、 "Dietrich"が記録されました。さらに、グローバル変数名が "Dietrich"に変更されました。 –

+0

もちろん、これは理由を説明していませんか? : 'name =" Dietrich "はまだグローバルです! –

1

、あなたは現在スコープで変数をインスタンス化しています。最初のケースではuser関数のスコープです。

varを使用しない場合、その変数をそのスコープ(function)に設定する必要はありません。すでに現在のスコープ(globally)の変数name外をインスタンス化するので、あなたが得るその変数としてname

var name = "Paul"; 
function users() { 
// var name; is essentially hoisted to here - the top of the current scope 
    if (!name) { 
     (var) name = "Jack"; // that hoisted var is set here 
    } 
    console.log(name); 
} 
users(); //outputs "Jack" 

その他の場合:

var name = "Paul"; 
function users() { 
    if (!name) { 
     name = "Jack"; // name is hoisted outside of the scope, 
         // but it already is declared as "Paul" 
    } 
    console.log(name); 
} 
users(); //outputs "Paul" 
+0

'var name =" Jack "' doesn変数が宣言されているだけです。 'var name;'や 'var name = undefined'と同じです。 –

+0

はい、正しいです、キャッチのおかげで、 – JordanHendrix

-1

それはオーダーです!

優先順位。解析時間中のドキュメントコードでは、関数はコードの実行が開始される前に評価されます。しかし、宣言された変数は、任意のコンテキストで優先順位が高くなります。関数は、すべての変数がインスタンス化された後にのみ実行することができます。

これは、宣言された変数 "name"を持つ関数が、そのローカル名の値を返している理由です。それはすでに存在しており、関数は外部スコープ内のその値を 'ルックアップ'する必要はないからです。


より深く理解するためにEDIT

、同じ例より興味深い例はここにある:

var name = "Paul"; 

    function users() { 
      name = "Dietrich"; 
     if (!name) { 
      var name = "Jack"; 
     } 
     console.log(name); 
    } 

users(); // outputs "Dietrich" 
console.log(name); // again outputs "Paul" 

だから何が起こったのか?

name = "Dietrich"は、グローバル 'name'変数の値を対象とする宣言ではありませんか?

なぜ、この同じ機能は以前と同じように「ジャック」を返すことができないのですか?または、なぜ突然出力が突然 "ジャック"ではなく "ポール"ではなく、奇妙で完全に予期しない "ディートリッヒ"ですか?

- これは、関数のセマンティクスとその条件付きの推測に従うものではなく、 "Paul"をリターニングして "Jack"を保持したのと同じ理由によるものです。

上記の理由からです。関数宣言の最初の視野と行には、グローバル "ポール" を明確にターゲットにしたname = "Dietrich"があります。すでに変数 "name"が利用可能であるため、 "Jack"の実行を妨げる追加の予防措置、条件があります。外側の範囲。しかし、役に立たない...

グローバルな "ポール"はまだ損なわれていません。

Weeは、 "name"変数に "Dietrich"を外部スコープから変数として割り当てます。 var(s)は関数の前で評価され、関数本体の宣言が実行を開始するよりずっと前になるからです。

そして、if(condition){ doesn't create a scope of its own }以降、その関数本体の深さは「名前」変数を宣言しても問題ありません。すべての方程式は今解決されました。

name = "Dietrich"は、 'name'変数がすでにこの(ローカル)関数スコープに存在するため、外部スコープのグローバル 'name'を変更しません。通常、 "Dietrich"はヒッチハイカーではなくローカル "Jack"宇宙の "ポール"。 var nameはすでに現在のスコープのどこかで定義されているからです。

「予期しない」「ジャック」を返すのと同じ理由です。それだけです。

+0

誰が文盲で、スレッド上で唯一の正しい答えを投票したかというと非常に馬鹿だ。 –