5

それは非常に特殊な状況であるか、私が異常に愚かであるため、正確にこれに適したタイトルが何であるかはわかりませんでした.

これが私がやろうとしていることです。

HTML5 で新しいシンプルな<meter>タグを作成します。主な問題は私のjavascriptにあります。私のjavascriptでメータータグの値を徐々に増やしようとしています。しかし、どういうわけか、それは私が望むようには機能しません。

JavaScript。

for (var i = 0; i <= 10; i++) {
    var a = document.getElementById("mtr1");
    setTimeout(function () {
        console.log(i);
        a.value = i;
    }, 250);
}

メーターの値を 250 ミリ秒ごとに徐々に上げようとしていますが、これは起こりません。代わりに、メーターは 10 にまっすぐジャンプします。

私が興味を持ったのはi、コンソールで得た価値でした。101,2,3...10 ではなく、 のインスタンスを取得しました。

なぜこれが起こるのですか?

フィドル

4

9 に答える 9

7

これは JavaScript クロージャの古典です。これiは、変数のコピーではなく、変数への実際の参照です。ループを繰り返した後、値は 10 になります。これが、すべてのログ呼び出しがログに 10 を書き込む理由です。
これはうまくいくはずです:

for (var i = 0; i <= 10; i++) {
    var a = document.getElementById("mtr1");
    setTimeout(function (i) {
        return function() {
            console.log(i);
            a.value = i;
        };
    }(i), 250 * i);
}

ここで最も内側iにあるのはsetTimeout、ループ本体で宣言した変数ではなく、のコールバック引数です。

于 2013-11-06T13:13:25.280 に答える
5

誰もsetIntervalを使用していないので、これが私の解決策です( http://jsfiddle.net/Qh6gb/4/ ):

var a = document.getElementById("mtr1");
var i = 0;
var interval = setInterval(function () {
    console.log(i);
    a.value = ++i;
    if (i == 10) {
        clearInterval(interval);
    }
}, 250);
于 2013-11-06T13:15:10.520 に答える
3

setTimeoutあなたが説明した問題は、元のバージョンでの非同期呼び出しが for の値を見る前に発生10しますi。これは、コールバックが実行された時点での値であるためです。

したがって、これはクロージャーのスコープの問題です。これを機能させるには、次のようにする必要があります。

for (var i = 0; i <= 10; i++) {
    var a = document.getElementById("mtr1");
    (function (i, a) {
        setTimeout(function () {
          console.log(i);
          a.value = i;
        }, 250);
    })(i, a);
}

また、a常に同じなので、これはより良いはずです:

var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
    (function (i) {
        setTimeout(function () {
          console.log(i);
          a.value = i;
        }, 250);
    })(i);
}

次に、カウンターが「カチカチ音をたてている」ことを確認したい場合は、次のようにして表示します。

var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
    (function (i) {
        setTimeout(function () {
          console.log(i);
          a.value = i;
        }, 1000 * i);
    })(i);
}

http://jsfiddle.net/LDt4d/を参照してください

于 2013-11-06T13:15:15.117 に答える
2

これは、「非同期」である setTimeout を呼び出したために発生します。そのため、setTimeout は 10 回呼び出されますが、ループ全体が完了してから実行されます。したがって、各呼び出しで i = 10...

http://jsfiddle.net/Qh6gb/9/

解決策があります:

var i = 1,
    meter = document.getElementById("mtr1");

function increase() {
    meter.value = i++;
    console.log(i);
    if(i<=10) {
        setTimeout(increase, 250);
    }
}

setTimeout(increase, 250);
于 2013-11-06T13:11:41.643 に答える
0

ループのすべてのステップでクロージャーを宣言する代わりに、関数内で for ループを実行します。

JSFIDDLE: http://jsfiddle.net/Qh6gb/3/

var a = document.getElementById("mtr1");
setTimeout(function () {      
    for (var i = 0; i < 10; i++) {
        console.log(i);
        a.value = i;
    }
}, 250);
于 2013-11-06T13:12:55.323 に答える
-1

すべてが同時に開始される複数の関数を作成しています。正確な遅延を得るには、タイマーに i を掛けます。

for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
    console.log(i);
    a.value = i;
}, 250 * i);
}
于 2013-11-06T13:14:13.910 に答える