6

5 つの関数呼び出しをずらして設定しようとしています (1 秒間隔で発生します)。その部分はうまく機能します。うまくいかないのは、値 0 ~ 4 をコールバック関数に渡すことができないことです。毎回「5」を渡すだけです。原因と修正方法がわかりません。

コード:

​function callback(num)
{
    console.log(num);
}

for (var i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000)
    setTimeout(function() { callback(i); }, loadDelay);

結果:

5
5
5
5
5

望ましい結果:

0
1
2
3
4
4

4 に答える 4

12

それは、クロージャーを作成するためです。したがって、同じインスタンスをsetTimeout共有するために渡す関数。i標準 (IE ではない) をサポートするブラウザーでは、次のことが可能です。

setTimeout(callback, loadDelay, i);

参照: http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers

それ以外の場合は、実際にbind関数への引数を指定する必要があります:

setTimeout(callback.bind(undefined, i), loadDelay);

参照: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

ブラウザーが ES5 メソッドをサポートしていない場合は、bind上記のリンクにあるシムを実装するか、次のようなことを手動で行うことができます。

setTimeout(function(index){
    return function() { callback(index) }
}(i), loadDelay);

しかし、使用すると読みやすくbindなり、シムを実装する価値があると思います。実際にこれを使用できます: https://github.com/kriskowal/es5-shim

ネイティブで es5 をサポートしていないブラウザーに es5 機能を追加する (可能な場合)。

于 2012-04-18T20:52:32.510 に答える
6

ラムダ/関数式を使用して、現在の値をキャプチャします。例えば

for (var i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000) {
  var doCall = function (j) {
    setTimeout(function() { callback(j); }, loadDelay);
  }
  doCall(i);
}

ここでの問題はi、ループのすべての反復に対して値が 1 つしかないことです。JavaScript の変数は、ブロック内で宣言できますが、関数スコープを持ちます。これはi、関数全体で有効であることを意味します。

問題を説明するために、以下のコードがサンプルとまったく同じように実行されると考えてください

var i;
for (i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000) {
  ...
}

私のソリューションは、新しい関数を導入し、新しい変数の有効期間を導入するため機能しjます。これにより、コールバックiで使用する関数の現在の値が保存されます。setTimeout

于 2012-04-18T20:40:46.413 に答える
4

i変数のスコープにより、渡すにはクロージャーが必要でした。閉鎖に関するいくつかの良い情報については、この記事これもチェックしてください。

ライブデモ

function callback(num)
{
    console.log(num);
}

for (var i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000)
    setTimeout((function(num){return function(){
           callback(num);
        }
    })(i), loadDelay);​
于 2012-04-18T20:42:20.687 に答える
0

setTimeout は、いくつかの奇妙なスコープの問題を引き起こします。Frame.jsは、この種の混乱の一部を解決するように設計されており、これも機能します [更新]:

function callback(num) {
    console.log(num);
}

for (var i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000) {
    Frame(function(next, i){
        setTimeout(function() { callback(i); }, loadDelay);
        next();
    }, i);
}
Frame.init();
于 2012-04-18T20:41:52.987 に答える