15

可能重复:
循环内的 Javascript 闭包 - 简单的实际示例

看到很多帖子谈论setTimeout和关闭,但我仍然无法传递一个简单的 for 循环计数器。

for (i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i);
  }, Math.floor(Math.random() * 1000));
}

5
5
5
5
5

想拥有

0
1
2
3
4

怎么了 ?
请不要发火,我以为我已经理解了这个setTimeout()故事,但显然没有。

4

3 回答 3

18

您可以使用闭包来保持i对循环内当前值的引用:

for (i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function () {
            console.log(i);
        }, Math.floor(Math.random() * 1000));
    })(i); //Pass current value into self-executing anonymous function
}​

但是,这不太可能按顺序打印数字,因为您使用了随机超时(您可以i * 1000改为使用以升序打印数字,相隔一秒)。

这是一个工作示例

于 2012-04-20T07:52:39.257 回答
4

您需要传递isetTimeout. 当你的第一个方法被执行时,i已经设置为 5。

由于您的超时因调用而可变Math.Random(),因此超时将有所不同,并且您不会按照您期望的顺序获得它们。

这是一个工作示例

for (i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);
    })(i);
}

更改Math.floor(Math.random() * 1000)为简单地1000确保函数按照您期望的顺序执行。

于 2012-04-20T07:52:04.407 回答
3

您需要将“有趣”的代码包装在一个函数中,该函数关闭i并将其复制到局部变量中:

for (i = 0; i < 5; i++) {
  (function() {
    var j = i;
    setTimeout(function () {
      console.log(j);
    }, Math.floor(Math.random() * 1000));
  })();
}

“中间”函数调用强制将值j固定在调用函数的点,因此在每个setTimeout回调中,值j是不同的。

于 2012-04-20T07:52:37.690 回答