62

2毎回以下のアラート。

function timer() {
    for (var i = 0; i < 3; ++i) {
        var j = i;
        setTimeout(function () {
            alert(j);
        }, 1000);
    }
}

timer();

を setTimeout の個々のスコープにvar j = i;設定するべきではありませんか?j

一方、私がこれを行うと:

function timer() {
    for (var i = 0; i < 3; ++i) {
        (function (j) {
            setTimeout(function () {
                alert(j);
            }, 1000);
        })(i);
    }
}

timer();

警告します0, 1,本来2あるべきように.

足りないものはありますか?

4

3 に答える 3

35

Javascript には関数スコープがあります。この意味は

for(...) {
    var j = i;
}

と同等です

var j;
for(...) {
    j = i;
}

実際、これは Javascript コンパイラが実際にこのコードを処理する方法です。そしてもちろん、これはあなたの小さな「トリック」が失敗する原因jとなります. の関数setTimeoutが呼び出される前にインクリメントされるためです.ji

Javascript にブロック スコープがあれば、jすべての反復内で新しい変数になるため、トリックが機能します。

あなたがする必要があるのは、新しいスコープを作成することです:

for(var i = ...) {
    (function (j) {
        // you can safely use j here now
        setTimeout(...);
    })(i);
}
于 2013-11-11T19:18:46.057 に答える
6

IIFE の代わりに関数ファクトリがあります。

function timer() {
    for (var i = 0; i < 3; ++i) {
        setTimeout(createTimerCallback(i), 1000);
    }
}

function createTimerCallback(i) {
    return function() {
       alert(i);
    };
}

timer();

そうは言っても、これは javascript タグで最も多く寄せられる質問の 1 つです。見る:

于 2013-11-11T19:26:10.363 に答える
3

別の方法は、(通常は乱用される) キーワードを使用することwithです。

function timer() {
    for (var i = 0; i < 3; ++i) {
        with({j: i}) {
            setTimeout(function () {
                alert(j);
            }, 1000);
        }
    }
}

timer();

関数のように新しいスコープを作成しますが、厄介な構文はありません。ここで初めて見ました: JavaScript の「with」ステートメントの正当な用途はありますか?

于 2013-11-11T19:41:46.887 に答える