変数setTimeout
関数を渡して、それを使って何かをしたいです。私がそれの値を警告するときi
、私が予期していなかった数を私に示します。何が間違っているのですか?1から8までのログ値が必要です。
var end=8;
for (var i = 1; i < end; i ++) {
setTimeout(function (i) {
console.log(i);
}, 800);
}
変数setTimeout
関数を渡して、それを使って何かをしたいです。私がそれの値を警告するときi
、私が予期していなかった数を私に示します。何が間違っているのですか?1から8までのログ値が必要です。
var end=8;
for (var i = 1; i < end; i ++) {
setTimeout(function (i) {
console.log(i);
}, 800);
}
これを解決する標準的な方法は、ファクトリ関数を使用することです。
var end=8;
for (var i = 1; i < end; i ++) {
setTimeout(makeResponder(i), 800);
}
function makeResponder(index) {
return function () {
console.log(index);
};
}
そこで、ループ内で呼び出す と、変数ではなく、makeResponder
渡された引数 ( ) を閉じる関数が返されます。(これは重要です。無名関数から引数を削除しただけでは、コードは部分的に機能しますが、すべての関数は、最初にスケジュールされたときではなく、実行されたときの値を参照します;あなたの例では、'd all see .)index
i
i
i
8
更新以下のコメントから:
...そのように呼んだら正しい
setTimeout(makeResponder(i),i*800);
でしょうか?
はい、最後の呼び出しよりも約 800 ミリ秒遅れて各呼び出しを発生させることが目標である場合、それは機能します。
やってみ
setTimeout(makeResponder(i),setInterval(i));function setInterval(index) { console.log(index*800); return index*800; }
たけどうまく動かない
あなたはsetInterval
そのように使用しませんし、おそらくこれにはまったく使用したくないでしょう。
さらなる更新:あなたは以下に言いました:
最初の繰り返し印刷 8 遅延 8 秒、2 回目の繰り返し印刷 7 遅延 7 秒 ........印刷 2 遅延 2 秒 ...印刷 0 遅延 0 秒が必要です。
2 番目のタイムアウトを使用して、上記の原則を再度適用するだけです。
var end=8;
for (var i = 1; i < end; i ++) {
setTimeout(makeResponder(i), i * 800);
}
function makeResponder(index) {
return function () {
var thisStart = new Date();
console.log("index = " + index + ", first function triggered");
setTimeout(function() {
console.log("index = " +
index +
", second function triggered after a further " +
(new Date() - thisStart) +
"ms delay");
}, index * 1000);
};
}
これで、これを進めるために必要なすべてのツールが揃ったと思います。
あなたの問題は、しばらくして関数が起動しi
たときに変数を参照していて、それまでに の値が変更されていることです(ループの最後に移動しています。各 setTimeout を適切な値の に保つには、キャプチャする必要がありますコールバックごとに個別にその値。 setTimeout()
i
for
i
i
setTimeout()
ファクトリ関数を使用した前の回答はそれで問題ありませんが、自己実行関数はファクトリ関数よりも入力して追跡するのが少し簡単だと思いますが、両方ともクロージャで必要な変数をキャプチャして静的値を参照できるため、両方とも機能します。 setTimeout コールバックで。
この問題を解決するために自己実行関数がどのように機能するかを次に示します。
var end=8;
for (var i = 1; i < end; i ++) {
(function (index) {
setTimeout(function() {
console.log(index);
}, 800);
})(i);
}
の値に比例してタイムアウト遅延を設定するには、次のi
ようにします。
var end=8;
for (var i = 1; i < end; i ++) {
(function (index) {
setTimeout(function() {
console.log(index);
}, index * 800);
})(i);
}
自己実行関数には の値が渡され、i
その値を含むその関数内の引数には名前が付けindex
られるため、参照しindex
て適切な値を使用できます。
ES6 で let を使用する
Javascript の ES6 (2015 年にリリース) では、ループ内で使用できlet
、ループfor
の反復ごとに新しい個別の変数が作成されfor
ます。これは、次のような問題を解決するためのより「現代的な」方法です。
const end = 8;
for (let i = 1; i < end; i++) { // use "let" in this line
setTimeout(function() {
console.log(i);
}, 800);
}
これが機能しない主な理由は、 のsetTimeout
後に実行するように設定されている800
と のスコープのためですi
。
実行するまでに、 which の値i
はすでに変更されています。したがって、決定的な結果は得られませんでした。TJ が言ったように、これを回避する方法はハンドラー関数を使用することです。
function handler( var1) {
return function() {
console.log(var1);
}
}
var end = 8;
for (var i = 1; i < end; i++) {
setTimeout(handler(i), 800);
}
setTimeout
accepts variables as additional arguments:
setTimeout(function(a, b, c) {
console.log(a, b, c);
}, 1000, 'a', 'b', 'c');
EDIT: In your example, the effective value of i
will likely be 8
, since the function is merely to be called after the loop has finished. You need to pass the current value of i
for each call:
var end=8;
for (var i = 1; i < end; i ++) {
setTimeout(function (i) {
console.log(i);
}, 800, i);
}