闭包

闭包的定义

  • 闭包是一个函数和其声明词法作用域的结合 --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个值,当执行对应函数的时候就会往上找自己对应的临时变量.

你可能感兴趣的:(闭包)