JavaScript变量绑定和循环

时间:2009-11-04 20:20:46

标签: javascript loops closures scope

考虑这样的循环:

for(var it = 0; it < 2; it++)
{
    setTimeout(function() {
        alert(it);
    }, 1);
}

输出结果为:

=> 2
=> 2

我希望它是:0,1。我看到两种解决方法:

解决方案#1。

这个基于我们可以将数据传递给setTimeout的事实。

for(var it = 0; it < 2; it++)
{
    setTimeout(function(data) {
        alert(data);
    }, 1, it);
}

解决方案#2。

function foo(data)
{
    setTimeout(function() {
        alert(data);
    }, 1);
}

for(var it = 0; it < 2; it++)
{
    foo(it);
}

还有其他选择吗?

4 个答案:

答案 0 :(得分:43)

除了你提出的两种方式之外,其实并不多,但这是另一种

for(var it = 0; it < 2; it++)
{
    (function() {
        var m = it;   
        setTimeout(function() {
            alert(m);
        }, 1);
    })(); 
}

基本上,您需要在闭包中捕获变量值。此方法使用立即调用的匿名函数捕获局部变量it中的外部变量值m

这是一个 Working Demo 。将 / edit 添加到网址以查看代码

答案 1 :(得分:14)

使用let关键字,您可以完全解决这个问题:

for(let it = 0; it < 2; it++)
{
    setTimeout(function() {
        alert(it);
    }, 1);
}

答案 2 :(得分:1)

与上述解决方案类似,但在setTimeout函数内部自行调用

for(var it = 0; it < 2; it++)
{
    setTimeout(function(cur) {
        return function(){
           alert(cur);
        };
     }(it), 1);
 }

答案 3 :(得分:1)

与其他解决方案类似,但在我看来更干净:

for (var it = 0; it < 2; it++) {
  // Capture the value of "it" for closure use
  (function(it) {
     setTimeout(function() {
       alert(it);
     }, 1);
  // End variable captured code
  })(it)
}

这为捕获保留了相同的变量名称,并为整个循环执行此操作,将其与超时设置的逻辑分开。如果你想在块中添加更多逻辑,你可以轻而易举地做到这一点。

我唯一不喜欢解决方案的是最后重复“它”。