15

重複の可能性:
ループ内のJavascriptクロージャ-簡単な実用例

クロージャについて話している多くの投稿を見ましsetTimeoutたが、それでも単純なforループカウンターを渡すことができません。

for (i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i);
  }, Math.floor(Math.random() * 1000));
}

与える

5
5
5
5
5

持っていたい

0
1
2
3
4

どうしたの ?
炎上しないでください、私は物語を理解したと思いましsetTimeout()たが、どうやら理解していません。

4

3 に答える 3

18

クロージャーを使用してi、ループ内の現在の値への参照を保持できます。

for (i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function () {
            console.log(i);
        }, Math.floor(Math.random() * 1000));
    })(i); //Pass current value into self-executing anonymous function
}​

ただし、ランダムなタイムアウトを使用するため、これは番号を順番に出力する可能性は低いです (i * 1000代わりに使用して、番号を 1 秒間隔で昇順で出力することができます)。

これが実際のです。

于 2012-04-20T07:52:39.257 に答える
4

iで使用されている関数に渡す必要がありsetTimeoutます。最初のメソッドが実行されるまでに、iはすでに5に設定されています。

の呼び出しによりタイムアウトが変動するため、Math.Random()タイムアウトは異なり、期待した順序でタイムアウトを取得することはできません。

これが実際の例です

for (i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);
    })(i);
}

に変更Math.floor(Math.random() * 1000)する1000と、関数が期待どおりの順序で実行されるようになります。

于 2012-04-20T07:52:04.407 に答える
3

i「興味深い」コードを閉じてローカル変数にコピーする関数でラップする必要があります。

for (i = 0; i < 5; i++) {
  (function() {
    var j = i;
    setTimeout(function () {
      console.log(j);
    }, Math.floor(Math.random() * 1000));
  })();
}

「中間」関数呼び出しはj、関数が呼び出された時点で の値を強制的に固定するため、各setTimeoutコールバック内で の値jは異なります。

于 2012-04-20T07:52:37.690 に答える