闭包

作者: e81bcd463937 | 来源:发表于2018-08-06 17:03 被阅读0次

    闭包的定义

    • 闭包是一个函数和其声明词法作用域的结合 --MDN
    • 关于闭包的解释和理解各不相同在此引用MDN给出的定义作为参考



    词法作用域

    • 函数在执行的过程中,先从自己内部找变量
    • 如果找不到,再从创建当前函数所在的作用域(词法作用域)去找, 以此往上
    • 注意找的是变量的当前的状态
      函数连同它作用域链上的要找的这个变量,共同构成闭包

    简单点,闭包就是一个变量,这个变量可以临时存储数据,一般来说和一个函数同时存在.

    • 一般情况下使用闭包主要是为了
    1. 封装数据
    2. 暂存数据


    文字叙述太抽象了,下面我们来看一个典型的闭包案例.

    一个典型的闭包案例
    function car() {
      var speed = 0
    
      function fn() {
        speed++
        console.log(speed)
      }
      return fn
    }
    
    var speedUp = car()
    speedUp() //1
    speedUp() //2
    
    • 一般来说,在car执行完成后内部的局部变量就会被销毁, speed将不复存在, 因为引擎启用了垃圾回收器,在内存不再被使用时来回收它们。但是闭包不会让这一切发生。在car里面再声明一个函数赋值给speedUp. 全局作用域是一直存在的, speedUp也就一直存在, 那么fn也就一直存在, fn在使用car内部的speed所以speed也不会被销毁. 当我们执行speedUp就是在执行fn,fn内部没有speed就会从上一级的词法作用域去找, 也就是car内部的speed. 这就导致闭包出现.


    那么这么好的东西到底有什么用呢??
    • 当我们调用speedUp这个函数的时候,可以把speed加1,这个变量就被暂存下来,我们无法直接访问这个变量,但是我们可以操作它,并且不会被销毁,speed封装成功.


    这就是一个典型的闭包


    闭包相关案例

    这是一个常见的笔试题

    如下代码输出多少?如果想输出3,那如何改造代码?
    var fnArr = [];
    for (var i = 0; i < 10; i++) {
      fnArr[i] = function () {
        return i
      };
    }
    console.log(fnArr[3]()) // 10
    
    为什么输出10?
    • 我函们在做遍历时就赋值了, 但数内部并没有执行执行, 我们执行fnArr[3]时就等于执行fnArr[i]然后return i, 此时函数内部没有i, 它会从创建这个函数的词法作用域去找这个i,因为for循环并不是一个函数所以它的词法作用域就是全局作用域, 全局作用域中for循环完成后,i变成10, 他找到了10输出.
    如果想输出3,那如何改造代码?
    var fnArr = []
    for (var i = 0; i < 10; i++) {
      fnArr[i] = (function (j) {
        return function () {
          return j
        }
      })(i)
    }
    console.log(fnArr[3]()) // 3
    
    • 这样就是相当于生成了10个闭包存了不同的10个值,当执行对应函数的时候就会往上找自己对应的临时变量.

    相关文章

      网友评论

          本文标题:闭包

          本文链接:https://www.haomeiwen.com/subject/dczwvftx.html