0

次の期待される実際の出力を含む次の小さなコード スニペットがあります。私の質問は静かでシンプルです。なぜこのシーケンスを印刷するのですか? 期待される出力を印刷するにはどうすればよいですか?

じゅ、

期待される結果:

0
1
2
0
1
2

実際の結果:

0
1
2
3
3
3

これはコードです:

var functions = [];

for (var i=0; i<10; i++) {
  console.log (i);
  functions.push (function () {
    console.log (i);
  });
};

for (var j=0; j<functions.length; j++) {
  functions[j] ();
};
4

3 に答える 3

5

i配列にプッシュする関数は、関数が作成されたときの値をログに記録しませんi。関数が呼び出されたときの値をログに記録します。

最初のループが終了すると、の値はiis10であるため、その後に呼び出される関数はいずれも value をログに記録します10

の値をさまざまな状態で保持したい場合はi、クロージャーを使用して値のコピーを作成できます。

for (var i=0; i<10; i++) {
  console.log (i);

  (function(){
    var copy = i;

    functions.push (function () {
      console.log (copy);
    });

  })();

};

ローカル変数copyは値を取得してi保持します。値をパラメーターとして関数に渡すこともできます。

for (var i=0; i<10; i++) {
  console.log (i);

  (function(copy){

    functions.push (function () {
      console.log (copy);
    });

  })(i);

};
于 2012-10-15T21:10:25.547 に答える
2

期待される結果は次のとおりです。

1
2
...
10
10
10
... 7 more times

この理由は簡単です。ループの内側は、ループの各反復でconsole.log(i)の値を正しく出力しています。i関数を作成して配列にプッシュするとfunctions、同じ variable に対してこれらの各関数が閉じられますi。ループの最後に、iループ条件を満たさなくなるため、i = 10真です。その結果、これらの関数のそれぞれが を実行しようとしconsole.log(i)ており、それぞれが値 10 を持つ同じ で閉じられているiため、値 10 が 10 回出力されることを期待する必要があります。

これを防ぐには、ループ内で直接関数を作成するのではなく、関数を返す関数を作成する必要があります。

var functions = [], i, j;
function createEmitter(i) {
  return function () {
    console.log(i);
  };
}

for (i = 0; i < 10; i++) {
  console.log(i);
  functions.push(createEmitter(i));
};

for (j = 0; j < functions.length; j++) {
  functions[j]();
};

現在、これらの作成された関数はそれぞれ、独自のプライベート スコープ変数で閉じられているため、問題が解決されています。

于 2012-10-15T21:12:01.130 に答える
0

結果と関数が一致するように、コード例を i < 3 に更新する必要があります。

配列にプッシュする関数はfunctions、変数 i への参照を格納しています。これは、一番上のループを実行した後、10 になります。したがって、実行すると、変数 i (10) を取得し、それを 10 回出力します。

これを実際に見る良い方法は次のとおりです。

for (var i=0; i<10; i++) {
  console.log (i);
};

console.log(i) //=> 10

変数を使用している場合は、変数が変更される可能性があることに注意してください。現在の値で固定されているわけではありません。あなたは他の何かへの参照を保持しているだけです。

この問題を修正するには、コードでこのタイプのマイナー リファクタリングを実行します (他の回答で既に追加のスコープが作成されているため、何か違うものを提供すると考えられます)。10 個の関数を格納するのではなく、数値を格納して 1 つの関数で実行するだけです。とにかく、これはそれを書くためのよりエレガントな方法であり、より少ないスペースを占有します. この例は、実際に問題を引き起こしているコードから抽象化されたものだと確信していますが、一般的なパターンは引き続き適用されます。

numbers = [];
for (var i=0; i<10; i++) {
  console.log (i);
  numbers.push(i);
};

numbers.forEach(function(i){
   console.log(i);
});
于 2012-10-15T21:23:37.840 に答える