封闭内部循环

时间:2016-07-20 03:09:20

标签: javascript closures

我知道使用此代码将0到9记录的方法之一:

编辑: http://localhost:4000/sesnors_home/John

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

Source

是让setTimeout自我调用并将i作为参数传递,如下所示:

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

但是我已经测试了setTImeout自我调用而没有通过i,它仍然有效:

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

jsfiddle

我的问题:

  1. 为什么即使没有将i作为参数传递也能正常工作?
  2. 是否有必要通过i

2 个答案:

答案 0 :(得分:8)

问题

这不是关闭。

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

setTimeout实际上需要一个函数作为参数,但是你让它立即调用。因此,它会立即记录i的值,而无需等待。 setTimeout现在返回您的匿名函数作为第一个参数undefined

同样在这里:

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

它立即执行,不等待10ms。您没有将i作为参数传递给唯一的区别,但它会在父范围内查找名为i的变量 - 并且只有一个。

如果您将时间设置为例如,您将看到立即调用您的匿名函数一秒钟(1000)。

解决方案

真正的关闭看起来像这样:

没有参数:你会看到10次10​​,因为在执行内部函数时循环已经完成,这意味着当时我等于10:

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

使用参数 - 您将获得预期结果:

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

答案 1 :(得分:3)

在所有的avobe代码中,您正在执行setTimeout中作为第一个参数给出的函数而不返回任何内容。那么你要回来的是undefined

在下面的代码中,我也是自我调用的,但返回一个函数,使setTimeout在特定的时间间隔i * 10之后执行。

这是闭包功能。检查控制台日志。它以毫秒为单位打印时间戳。差距为10毫秒。

for (var i = 0; i < 10; i++) {
  setTimeout((function(i) {
    return function() {
      console.log(i, performance.now() + 'ms');
    }
  })(i), i * 10)
}

其他信息 在评论部分,我有一个查询

  

什么是重点,当你可以把setTimeout放在一个匿名函数中?   所以我猜这是你建议的代码。   

for (var i = 0; i < 10; i++) {
    setTimeout(function() {
      console.log(i, performance.now() + 'ms');
    }, i * 10)
}

如果您运行此代码段,则每个日志的日志都会为10。这就是封闭之美。当您执行匿名函数

function() {
   console.log(i, performance.now() + 'ms');
}

它无法在当前范围内找到i并搜索其父范围。瞧,它找到了我,但不幸的是,循环已经完成了它的迭代,现在它的值= 10。所以每次记录10次。

这就是我们需要关闭的原因。