JavaScript之循环里的闭包

   之所以写这篇文章是因为很多人都遇到过这个坑,刚遇到的时候确实很困惑,不知道如何解决,在这篇文章里我用一个最简单的问题来举例这种问题的多种解决办法。
例题:每隔一秒输出一个递增的数字
刚拿到这个问题的时候相信都是一样的思维,for循环加延时:

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

结果并非我们所期望,而是每秒输出一个数字,但数字不是递增的,都是5,原因是什么呢?当我们延时等待的时候,for循环不会等待,而是一直执行下去,所以结果i是循环结束之后的i值而不是每一次参与循环的i值,在ES6之前,我们使用立即执行函数产生闭包来解决此类问题:

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

在每一次循环时,使用闭包将i值保留,所以最后结果是每一秒输出一个数字,并且递增
和上面方法类似,有下面这种写法:

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

和上面的方法一样,只不过是闭包的另一种写法,注意括号的位置:

(function () {
  //...
})();
(function () {
  //...
}());

这是ES6之前的写法,ES6加入了let,我们知道let是块级作用域,使用let在此处产生闭包相当方便,这也是let和var差别的一个重要例子:

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

当然,我们也可以把最上面的那个例子里的var直接改为let,效果是一样的:

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

上面四种方法可以解决此类问题,再遇到此类问题相信不会再迷惑了吧

猜你喜欢

转载自blog.csdn.net/qq_23158083/article/details/75340322