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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 20:37:51  来源:igfitidea点击:

Passing functions to setTimeout in a loop: always the last value?

javascriptsettimeout

提问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 sis 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;
}

View demo of it in action

查看它的实际演示

回答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;
}