javascript 如何将变量传递给 setTimeout 函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10217536/
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
How to pass a variable into a setTimeout function?
提问by CaptSaltyHyman
I'm trying to set five staggered function calls (happening one second apart). That part works fine. What doesn't work is, I can't pass values 0 through 4 into the callback function. It just passes '5' each time. I can't seem to figure out why and how to fix it.
我正在尝试设置五个交错的函数调用(相隔一秒)。那部分工作正常。不起作用的是,我无法将值 0 到 4 传递到回调函数中。每次只通过'5'。我似乎无法弄清楚为什么以及如何解决它。
Code:
代码:
?function callback(num)
{
console.log(num);
}
for (var i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000)
setTimeout(function() { callback(i); }, loadDelay);
Result:
结果:
5
5
5
5
5
Desired result:
想要的结果:
0
1
2
3
4
回答by ZER0
That's because you create a closure. So the function you pass to setTimeout
share the same i
instances. In the browser that supports the standards (not IE) you could have:
那是因为你创建了一个闭包。所以你传递的函数setTimeout
共享相同的i
实例。在支持标准(非 IE)的浏览器中,您可以:
setTimeout(callback, loadDelay, i);
See: http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers
请参阅:http: //www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers
Otherwise you have to actually bind
the argument to the function:
否则,您必须实际bind
使用函数的参数:
setTimeout(callback.bind(undefined, i), loadDelay);
See: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
请参阅:https: //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
If the browser doesn't support ES5 bind
method, you can either implement the shim present in the link above, or manually doing something like:
如果浏览器不支持 ES5bind
方法,您可以实现上面链接中存在的 shim,或者手动执行以下操作:
setTimeout(function(index){
return function() { callback(index) }
}(i), loadDelay);
But I would say it's more readable using bind
and it's worthy to implement the shim. You can actually use this: https://github.com/kriskowal/es5-shim
但我会说使用它更具可读性bind
,并且值得实施垫片。你实际上可以使用这个:https: //github.com/kriskowal/es5-shim
To add es5 capabilities (where is possible) in the browser that don't support es5 natively.
在本机不支持 es5 的浏览器中添加 es5 功能(在可能的情况下)。
回答by JaredPar
Use a lambda / function expression to capture the current value. For example
使用 lambda / 函数表达式来捕获当前值。例如
for (var i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000) {
var doCall = function (j) {
setTimeout(function() { callback(j); }, loadDelay);
}
doCall(i);
}
The problem here is that there is only 1 i
value for all iterations of the loop. Variables in javascript have function scope even though you can declare them inside of a block. This means i
is alive for the entire function.
这里的问题是i
循环的所有迭代只有 1 个值。javascript 中的变量具有函数作用域,即使您可以在块内声明它们。这意味着i
对整个函数都是有效的。
To illustrate the problem consider the below code executes exactly the same as your sample
为了说明问题,请考虑以下代码的执行与您的示例完全相同
var i;
for (i = 0, loadDelay = 1000; i < 5; ++ i, loadDelay += 1000) {
...
}
My solution works because it introduces a new function and hence a new variable lifetime for j
. This saves the current value of i
in the function for use in the setTimeout
callback
我的解决方案有效,因为它引入了一个新函数,因此为j
. 这将保存i
函数中的当前值以供setTimeout
回调使用
回答by Loktar
You needed a closure in order to pass i
due to variable scoping. Check out this article, and this one as wellfor some good information on closures.
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);?
回答by BishopZ
setTimeout creates some odd scoping problems. Frame.jswas designed to resolve some of this kind of confusion, this also works [updated]:
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();