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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 09:05:04  来源:igfitidea点击:

How to pass a variable into a setTimeout function?

javascript

提问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 setTimeoutshare the same iinstances. 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 bindthe 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 bindmethod, 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 bindand 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 ivalue for all iterations of the loop. Variables in javascript have function scope even though you can declare them inside of a block. This means iis 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 iin the function for use in the setTimeoutcallback

我的解决方案有效,因为它引入了一个新函数,因此为j. 这将保存i函数中的当前值以供setTimeout回调使用

回答by Loktar

You needed a closure in order to pass idue to variable scoping. Check out this article, and this one as wellfor some good information on closures.

i由于变量范围,您需要一个闭包才能通过。看看这篇文章,而这一次,以及对关闭一些有用的信息。

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);?

回答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();