# 闭包

闭包是指有权访问另一个函数作用域中的变量的函数。

# 原理

闭包的实现原理,其实是利用了作用域链的特性,我们都知道作用域链就是在当前执行环境下访问某个变量时,如果不存在就一直向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。

# 简单实现

function print() {
  var a = 1;
  return function() {
    return ++a;
  };
}
let p = print();
console.log(p()); // 2
console.log(p()); // 3
console.log(p()); // 4
1
2
3
4
5
6
7
8
9
10

# 原理解释说明

在上面的例子中 print函数中的匿名函数有作用域链有三层。0:自己,1:print函数,2:全局。尽管匿名函数被return出去,但是他的作用域链在初始化的时候就已经完成了(被保存在了内存的[[Scope]]属性中)。所以尽管匿名函数在全局环境中被调用,但是他还是能获取到print函数中的变量。

提问

可能有的同学会产生疑问,按照js的垃圾回收机制,print()函数调用完成后,就应该回收销毁局部变量,这里为什么匿名函数还能获取到局部变量a的累加值呢?

结论

这是因为匿名函数的作用域链任然在引用print函数中的变量,导致垃圾回收机制GC不会回收a变量,所以我们才能得到a变量的累加值。

提问

那我们什么时候能让a变量被垃圾回收呢?

回答

print=null,将p设置为null时,解除了匿名函数对print函数的引用将print设置为null时,解除了匿名函数对a的引用,就等于通知垃圾回收例程将其清除。

# 作用

作用1:隐藏变量,避免全局污染

作用2:可以读取函数内部的变量

同时闭包使用不当,优点就变成了缺点:

缺点1:导致变量不会被垃圾回收机制回收,造成内存消耗

缺点2:不恰当的使用闭包可能会造成内存泄漏的问题

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

# 推荐文献

Last Updated: 3/4/2024, 3:06:40 PM