2009-11-04 58 views
23

考虑这样循环:JavaScript变量的结合和环

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

是否还有其他选择吗?

回答

42

算不上什么比你已经提出了,但这里的两种方式更是另一个

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

本质上讲,你需要捕获在一个封闭的变量值。此方法使用立即调用的匿名函数来捕获局部变量m中的外部变量值it

这里有一个Working Demo玩。添加/编辑到URL查看代码

+4

+1。但是,您可以通过将方法签名更改为:'function(m){/ * code * /})(it);' – Alan 2012-11-24 21:29:47

+0

+1,但可以有人解释为什么这是行得通的? – 2014-09-17 10:06:01

+1

@digorydoo循环中声明的函数包装在括号中,后跟一组圆括号,用于立即调用该函数。因为变量的作用范围是它们被声明的函数(或者如果没有在函数内声明,则是全局作用域),每次迭代中'it'的值被赋值给作为作用范围的'm'变量立即。 – 2014-09-17 10:35:02

1

与上述相类似的解决方案,但setTimeout函数

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

随着let关键字的内部自我调用就可以解决这个问题彻底:

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

但在JavaScript中没有命名为'let'的关键字它在打字稿中我认为 – 2017-06-08 11:35:46

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) 
} 

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

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