javascript 在循环中将函数传递给 setTimeout:总是最后一个值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6425062/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing functions to setTimeout in a loop: always the last value?
提问by Dee2000
I'm trying to use setTimeout to execute an anonymous function that I pass information into and I'm having trouble. This (hard-coded version) would work just fine:
我正在尝试使用 setTimeout 执行一个匿名函数,我将信息传递给该函数,但遇到了问题。这个(硬编码版本)可以正常工作:
setTimeout(function(){alert("hello");},1000);
setTimeout(function(){alert("world");},2000);
But I'm trying to take the hello and world from an array and pass them into the function without (a) using global variables, and (2) using eval. I know how I could do it using globals or eval, but how can I do it without. Here is what I'd like to do (but I know it won't work):
但是我试图从数组中获取 hello 和 world 并将它们传递到函数中,而没有 (a) 使用全局变量,以及 (2) 使用 eval。我知道如何使用 globals 或 eval 来做到这一点,但我怎么能没有。这是我想要做的(但我知道它行不通):
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout( function(){alert(strings[i]);}, delay);
delay += 1000;
}
Of course strings[i] will be out of context. How can I pass strings[i] into that anonymous function without eval or globals?
当然,strings[i] 将脱离上下文。如何将 strings[i] 传递给没有 eval 或 globals 的匿名函数?
回答by Alnitak
This is the very frequently repeated "how do I use a loop variable in a closure" problem.
这是经常重复的“我如何在闭包中使用循环变量”的问题。
The canonical solution is to call a function which returns a function that's bound to the current value of the loop variable:
规范的解决方案是调用一个函数,该函数返回一个绑定到循环变量当前值的函数:
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout(
(function(s) {
return function() {
alert(s);
}
})(strings[i]), delay);
delay += 1000;
}
The outer definition function(s) { ... }
creates a new scope where s
is bound to the current value of the supplied parameter - i.e. strings[i]
- where it's available to the innerscope.
外部定义function(s) { ... }
创建一个新的范围,其中s
绑定到所提供参数的当前值 - 即strings[i]
-内部范围可以使用它。
回答by svinto
Just add a scope around the setTimeout call:
只需在 setTimeout 调用周围添加一个范围:
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
(function(s){
setTimeout( function(){alert(s);}, delay);
})(strings[i]);
delay += 1000;
}
回答by Pointy
You could write a separate function to set up the timeout:
您可以编写一个单独的函数来设置超时:
function doTimer(str, delay) {
setTimeout(function() { alert(str); }, delay);
}
Then just call that from the loop:
然后从循环中调用它:
var delay = 1000;
for(var i=0;i<strings.length;i++) {
doTimer(strings[i], delay);
delay += 1000;
}
回答by Ciaran
Although not as backward compatible as some of the other answers, thought I'd throw up another option.. this time using bind()!
虽然不像其他一些答案那样向后兼容,但我想我会抛出另一个选择..这次使用bind()!
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout(alert.bind(this, strings[i]), delay);
delay += 1000;
}
回答by Subdigger
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout( new Function('alert(strings[i]);'), delay);
delay += 1000;
}