2012-04-18 4 views
4

私は5つのずらした関数呼び出しを設定しようとしています(1秒間隔で起こっています)。その部分は正常に動作します。動作しないのは、0から4の値をコールバック関数に渡すことができないということです。それは毎回「5」を渡すだけです。私はそれを修正する理由と方法を理解できないようです。変数をsetTimeout関数に渡すにはどうすればいいですか?

コード:

​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 
+0

コールバックの値をインクリメントします。 setTimeoutメソッドが非同期であるので、あなたは常に5 – malletjo

答えて

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を使用して、より読みやすいと言うだろうし、それはシムを実装する価値があるのです。ネイティブES5をサポートしていないブラウザでは(可能である)ES5機能を追加するにはhttps://github.com/kriskowal/es5-shim

:あなたは実際にこれを使用することができます。

+0

グレートを持っている理由、これがあります!ニース&ショート、エレガント。 FirefoxとChromeで動作します。 – CaptSaltyJack

4

現在値をキャプチャするためにラムダ/関数式を使用します。例

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

のためにここでの問題は、ループのすべての反復のための唯一の1 i値があるということです。 javascript内の変数は、ブロック内で宣言することはできますが、関数スコープを持ちます。これは、関数全体に対してiが生きていることを意味します。問題を説明するために

は、それがjのための新しい機能、ひいては新しい変数生涯を紹介するので、私のソリューションが動作する以下のコードは

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

あなたのサンプルとまったく同じことを実行考えます。これにより、setTimeoutコールバックで使用する関数に現在の値iが保存されます。

0

setTimeoutは、奇妙なスコープの問題を引き起こします。

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(); 
3

あなたが原因変数のスコープにiを渡すために閉鎖を必要:Frame.jsが、これはまた、[更新]作品、混乱のこの種のいくつかを解決するために設計されました。閉鎖に関する良い情報については、this articlethis one as wellを参照してください。あなたはクロージャを作成するためです

Live Demo

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);​ 
関連する問題