• 闭包


    闭包应该是前段面试中经常碰到的面试题,很多人都会在这个问题上被问住。如果想要弄清楚就要掌握闭包的概念;

    首先看面试题:

    for (var i = 1; i <= 5; i++) {

      setTimeout( function timer() {

          console.log(i);

      }, 1000 );

    }

    上面的代码会输出什么?怎么改动上述代码,使其依次输出1、2、3、4、5

    答案是  程序会先输出一个"5",后面每隔1000毫秒输出一个6,

    setTimeout()相关知识

    在我们学习setTimeout的时候就知道,setTimeout有两个参数,第一个参数是回调函数,第二个参数是毫秒数,表示要执行回调函数所要延迟的时间。但我们还需要知道的是,setTimeout会返回一个Id,即这个定时器的Id,在上面的代码中其实已经创建了5个定时器,但是默认只返回了最后的一个Id,所以会先输出一个5。

    接下来就该讨论为什么会输出5个数字6,而不是1、2、3、4、5了。

    因为setTimeout()函数要等执行完函数调用栈中的代码,然后立即调用定时器。这是因为,我们的定时器都被放在了一个被称为队列的数据结构中,等待上下文的可执行代码运行完毕后,才开始运行定时器,也就是定时器才刚开始计时。所以在定时器的方法执行的时候,变量i已经变成了6,所以输出的全部是6。

    那么怎么样才能输出1、2、3、4、5呢?

    因为5个定时器所打印出来的是同一个i变量,所以想要实现输出不同的数字,就需要把每个定时器所访问的变量独立起来,这就用到了JavaScript的闭包。闭包用途很多,可以很好地区分开各个作用域,避免变量的混淆,但是滥用闭包也会导致性能问题。那么通过下面的修改就可以了;

    for (var i = 1; i <= 5; i++) {

        (function(i){

            setTimeout( function timer() {

                  console.log(i);

              },  1000 );

        })(i);

    }

    块级作用域--关键字let

    使用闭包可以得到正确的结果,原因就是改变了i的作用域,那如果我们把循环中的每个setTimeout都独立成一个作用域是不是也能实现同样的结果呢?我们都知道,在JavaScript中,每个函数是一个独立的作用域,但是“{}”是不能形成独立作用域的。

    在ES6中提出了一个新的关键字let,就可以声明一个仅对当前“{}”内部有作用的变量。输出的结果是一样。

    for (let i = 1; i <= 5; i++) {

      setTimeout( function timer() {

          console.log(i);

      }, 1000 );

    }

  • 相关阅读:
    自动装箱和==和equals
    4.1 java 类加载器
    23种设计模式
    ionic2打包 配置路径
    ionic2 native app 更新用户头像暨文件操作
    Spring Security三种认证
    maven设置本地仓库地址和设置国内镜像
    ps选框工具全解
    最长公共子序列问题
    内部排序算法的稳定性
  • 原文地址:https://www.cnblogs.com/snowhite/p/9172278.html
Copyright © 2020-2023  润新知