1

私はこのサンプルコードを持っています:

for (var i = 0; i < array.length; i++) {
    $.getJSON("http://someapi", { "one": two }, function (result) {
        array[i].value = result.value;
    });
}

ただし、コールバック関数の i 変数は、期待できるものに対応していません。for ループは非常に高速に実行されており、最初のコールバック関数が応答を受け取る前に終了しているため、i 変数はループ内のどこかにあるか、終了して配列の境界を超えています。

とにかく、変数をコールバック関数に渡す方法はありますか? このようなもの:

$.getJSON("http://someapi", { "one": two }, function (result, i) {
    array[i].value = result.value;
});
4

2 に答える 2

4
for (var i = 0; i < array.length; i++) {
    $.getJSON("http://someapi", { "one": two }, (function(j) {
        return function (result) {
            array[j].value = result.value;
        };
    })(i)); // Immediate invocation is your best friend
}

iそのように、コールバックを宣言するときに変数を渡すことができます (コードのように評価されるときではありません)。

于 2013-04-11T10:22:05.290 に答える
3

現在のインデックスを格納するための追加のクロージャを作成し、それを実際の関数内で使用すると、次のようにうまくいくはずです。

for (var i = 0; i < array.length; i++) {
    $.getJSON("http://someapi", {
        "one": two
    }, (function () { // added closure...
        var currentIndex = i; //...to allow declaration of additinal variables

        return function (result) {
            array[currentIndex].value = result.value; // use currentIndex here
        };
    })()); // () force immidiate execution
}

デモ- クロージャーを使用しない場合とクロージャーを使用する場合の結果の比較


DEMO を開いて をクリックRunし、コンソールの出力を確認します。

デモからのコード:

var array = [1, 2, 3, 4, 5];

// Wihtout closure i is not always as expected.
for (var i = 0; i < array.length; i++) {
    $.getJSON("#", {
        "one": 1
    }, function (result) {
        console.log('no-closure: ' + i);
    });
}

// With closure stored i (currenIndex) is in the expected order
for (var i = 0; i < array.length; i++) {
    $.getJSON("#", {
        "one": 1
    }, (function () {
        var currentIndex = i;
        return function (result) {
            console.log('closure: ' + currentIndex);
        };
    })());
}
于 2013-04-11T10:26:35.840 に答える