• 你不知道的JS系列 ( 15 ) - 循环和闭包


    要说明闭包,for 循环是常见的例子
    for (var i=1; i<=5; i++) {
      setTimeout(function timer() {
        console.log(i);
      }, 0)
    }

    延迟函数的回调会在循环结束时才执行,执行循环的时候,变量的值已经变成 6 了,因此会每次输出一个 6 来。我们认为循环中的每个迭代在运行时都会给自己捕获一个 i 的副本。但是根据作用域的工作原理,调用的都是同一个 i。它只有一个 i。如果将延迟函数的回调重复定义 5 次,完全不使用循环,同这段代码是等价的

    var i = 1;
    setTimeout(function timer() {
      console.log(i);
    }, 0)
    i = 2;
    setTimeout(function timer() {
      console.log(i);
    }, 0)
    i = 3;
    setTimeout(function timer() {
      console.log(i);
    }, 0)
    i = 4;
    setTimeout(function timer() {
      console.log(i);
    }, 0)
    i = 5;
    setTimeout(function timer() {
      console.log(i);
    }, 0)
    i = 6;

    输出了 5 次 6。我们需要更多的闭包作用域,保留每次对 i 的引用



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

    这里增加了一层作用域,但是这个作用域里面是空的,它需要自己的变量,用来存储 i 的值

    for (var i=1; i<=5; i++) {
      (function(){
        var j = i;
        setTimeout(
    function timer() {       console.log(j);     }, 0)   })() }

    行了,它能正常的工作了。可以对这段代码进行一些改进:

    for (var i=1; i<=5; i++) {
      (function(j){
        setTimeout(function timer() {
          console.log(j);
        }, 0)
      })(i)
    }

    为每个迭代都生成一个新的作用域,使得延迟函数的回调都持有内部变量的访问。换句话说,每次迭代我们都需要一个块作用域,let 可以用来劫持块作用域。本质上是将块作用域转换成一个可以被关闭的作用域

    for (let i=1; i<=5; i++) {
      let j = i;
      setTimeout(function timer() {
        console.log(j);
      }, 0)
    }

    这样跟多封闭一层作用域的效果是一样的。但是 for 循环头部的 let 声明还会有一个特殊的行为,这个行为让变量在循环中不止被声明依次,每次迭代都会声明。

    for (let i=1; i<=5; i++) {
      setTimeout(function timer() {
        console.log(i);
      }, 0)
    }
    很酷,块作用域和闭包联手便可天下无敌
     
  • 相关阅读:
    新浪微博数据抓取(java实现)
    在Tomcat下配置Solr 4.x 版本
    使用AWT组件实现验证码功能
    css自动换行
    CentOS6.5把MySQL从5.1升级到5.6后,MySQL不能启动
    centos绑定多个域名
    Centos下Yum安装PHP5.5,5.6,7.0
    CSS总结
    覆盖物
    高德地图插件
  • 原文地址:https://www.cnblogs.com/wzndkj/p/12364998.html
Copyright © 2020-2023  润新知