谈谈你对闭包的认识

关于回答这个问题,我们可以从四个方面入手:

  1. 什么是闭包
  2. 闭包解决了什么问题
  3. 闭包的应用场景
  4. 闭包的缺点

什么是闭包

一句话解释就是可以访问另一个函数作用域中变量的函数。

然后解释一下这句话,在JS的函数执行会形成一个作用域,执行完成作用域会销毁,但是闭包就不要一样了,由于闭包函数是函数内部的子函数,内部函数可以访问上级作用域,由于函数作用域中存在变量引用,所以执行完成不会立即销毁。

闭包解决了什么问题

  1. 可以读取函数内部的变量
  2. 让这些变量始终保持在内存中,函数调用后不会被清除。
let bar = function () {
  let local = '局部变量'
  return function () {
    return local
  }
}
var baz = bar()
console.log(baz())
console.log(baz())

一般而言执行bar后,局部变量就会随着作用域销毁,但是这里返回的是一个匿名函数,匿名函数可以访问上级作用域中的变量 local。bar的作用域发现变量有引用关系,就不会销毁了。虽然在外部作用域中无法直接访问local,但是若要访问,只要通过这个中间函数周转一下就可以访问。之后只要调用baz函数就可以获取local变量了,不管你执行多少次,问题在于一旦有变量引用这个中间函数,这个中间函数就不会释放,同时也会使原始的作用域得不到释放。

闭包的应用场景

通过闭包抑制变量,来保存变量的状态

function addCounter() {
   let counter = 0
   const myFunction = function () {
     counter = counter + 1
     return counter
   }
   return myFunction
 }
 const increment = addCounter()
 const c1 = increment()
 const c2 = increment()
 const c3 = increment()
 console.log('increment:', c1, c2, c3);
 // increment: 1 2 3

在这段代码中increment实际上就是闭包函数myFunction, 它一共运行了三次,第一次的值是1,第二次的值是2,第三次的值是3。这证明了,函数addCounter中的局部变量counter一直保存在内存中,并没有在addCounter调用后被自动清除。通过抑制变量实现数字的累加。

常考的面试题还有f(1)(2)(3)实现1+2+3

// 实现方法1,用闭包抑制变量,保存参数,当参数达到一定的个数进行求和操作
const add = (function (length) {
  let allArgs = [];
  function _add (...args) {
    allArgs = [...allArgs, ...args];
    if (allArgs.length >= length) {
      let res = allArgs.reduce((prev, cur) => prev + cur, 0);
      allArgs.length = 0
      return res;
    } else {
      return _add;
    }
  }
  return _add
})(3)

闭包的缺点

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,我们建议读者只在绝对必要时再考虑使用闭包。虽然像V8等优化后的JavaScript引擎会尝试回收被闭包占用的内存,但请大家还是要慎重使用闭包。

发布了254 篇原创文章 · 获赞 200 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/wu_xianqiang/article/details/105018652