4

以下が 1,2 を生成し、もう一方が 5 を生成する理由を誰か説明できますか? 両方とも 5 を生成するべきではありませんか?

//produces 1,2
(function () {

    var a = [5];

    function bar() {
        if (!a) {
          var a = [1, 2];
        }
        console.log(a.join());
    }

    bar();

})();

JS クロージャーに関するいくつかの記事を読んだことに基づいて、両方とも 5 を生成することを期待しています。

//produces 5
(function () {

    var a = [5];

    function bar() {
        if (a) {
          console.log(a.join());
        }
        else {
          console.log([1, 2].join())
        }
    }

    bar();

})();

ありがとう!

4

4 に答える 4

5

javascripts var hoistingにより、このコード:

(function () {
    var a = [5];
    function bar() {
        if (!a) {
          var a = [1, 2];
        }
        console.log(a.join());
    }
    bar();
})();

は、次のコードと同等です。

(function () {
    var a = [5];
    function bar() {
        var a; // a === undefined at this point
        if (!a) {
          a = [1, 2];
        }
        console.log(a.join());
    }
    bar();
})();

したがって、if条件がテストされると、a実際に(つまり、!a === true)になることがわかりますfalsey

于 2016-11-22T05:41:00.107 に答える
1

Jeromanda X は正しい答えを出しました。これはvar hoisting が原因です。よりよく説明するために追加したいと思います。

2つのコードブロックは、一方に新しい変数を作成し、もう一方には作成しなかったという点で異なります。公平を期すために、コードブロック#2を次のように変更する必要があります

//produces [1,2] now
(function () {

  var a = [5];

  function bar() {
      if (a) {
        console.log(a.join());
      }
      else {
        var a = [1,2];
        console.log(a.join())
      }
  }

  bar();

})();

両方のコード ブロックを省略していればvar、このスコーピングの問題に遭遇することはなかったでしょう。5

于 2016-11-22T06:11:36.783 に答える
1

再宣言を避け、トップ関数のようにvar a = [1, 2];初期化してください。a = [1, 2];@Jaromanda が説明したように、変数は JavaScript で巻き上げられます。

于 2016-11-22T05:45:01.827 に答える
-2

すべての関数が独自のコンテキストを作成し、独自のローカル変数やものを持つことができることを知っています。

したがってvar a = [5]、最上位の関数コンテキストのコンテキストで を記述すると、記述する可能性のある新しいネストされた関数のコンテキストで使用可能になり、アクセスできるようになると想定しています。

そして、これはおそらく「文書化されていない」「予期しない」動作に遭遇する場所です。

op の 1at の例

function bar(){
    if(!a) { 
           var a = [1,2];
          }
    console.log(a);
    }
>> 1,2

1,2 のローカル値を返すようにします。ここで、bar関数コンテキストのif条件がホスト関数変数aundefinedとして扱っていることがわかります。そのため、 !atrueに否定しています。

何故ですか?コメンテーターは巻き上げを主張します。しかし、何の巻き上げ?唯一の違いは条件付き引数にある同じ関数の 2 つのバージョンの最終結果または動作における巻き上げ原理の干渉はまったくありませ

巻き上げ!何の巻き上げ?「ホイスト」の場合 - !a操作は間違いなくfalseを返す必要があります。これは、ホストのすべての下位コンテキスト関数にアクセス可能な上位コンテキストで、 a がの値で既に定義されているためです。でも全く逆

if(!a [false] ) したがって、条件付きリターンからtrueの結果として、var キーを使用して、同じ名前変数の新しい宣言の実行を許可しています。より高い範囲で。

そして、そうすべきではありません。しかし、そうすべきです。

条件付きの if 引数を否定せずに同じことを試みると、次のようにエラーと代入の失敗が発生します。

 function bar(){
    if(a) { 
           var a = [1,2];
          }
    console.log(a);
    }
>> undefined

[!if(!!a) を使用する場合と同じ] 値 [1,2] を持つ新しいローカル 'a' 変数を作成できるように、a が true かどうかを尋ねていること以外は何も変更していません。

何が起こっている?!続行するためにa引数trueであることが明示的に必要なif条件は、関数bar のローカル コンテキストを検索して「下に登る」ことです。

何らかの理由で、ホスト関数の変数を再宣言し、ローカル コンテキストで同じ名前の新しい変数に初期化して値を割り当てることを拒否する試みとして処理されます。これは、ホスト変数を参照する条件式が宣言してローカル a に値を割り当てることを拒否しているため、混乱を招きます。

ただし、コンソール ログでは、ローカル変数 a が返されており、undefinedです。

これは予想外です。矛盾している; 反抗的だが一見正しい!ローカルa変数は初期化されましたが、最初は正しく値を取得できなかったため、正しいです。より高いコンテキストから 1 つを再宣言しようとしましたが、許可されませんでした。

唯一の良い点は、動作がブラウザー間で統一されているように見えることです。

于 2016-11-22T05:49:10.377 に答える