闭包,你到底有啥用?

7,283 阅读2分钟

前两天和同事吹水时,突然聊到闭包,这个概念很好理解但是又感觉好像没有完全理解的东西,一直没搞懂它究竟有什么用。

概念

先来看看闭包的概念

闭包是一个函数有权访问另一个函数(另一个作用域)中声明的变量,这个函数就叫闭包。

  • 优点:保存变量不受外界影响,形成不销毁的栈变量

  • 缺点:不当使用会导致内存泄漏

分析

保存私有变量不被污染

不受外界影响很好理解,举栗说明:

var a = '皮皮章'
function foo() {
    var a = 'foo'
    function fo() {
        console.log(a);
    }
    return fo
}

function f(p) {
    var a = 'f'
    p()
}

f(foo())  

答案(点击后展开):

'foo'
  1. f(foo())实际是将fo作为入参传递给f函数,
  2. fo使用了在父函数foo中声明的a,所以即便foo函数已经执行到return语句,变量a仍然不会被销毁
  3. fo函数就是一个闭包;
  4. fo函数在f函数中被调用时,依然会使用在foo函数中定义的a变量。

可以看到,形成闭包之后变量不会因为被重新声明赋值而受到影响,达到防止变量被污染的效果。

不销毁的栈内存

要理解不销毁的栈内存,首先要明白堆栈内存的概念,以及js内存销毁机制

  • 栈内存中保存:基本类型、引用类型的指针地址
  • 堆内存中保存:引用类型

通常情况,栈内存当中存储的变量,会在使用结束之后被js内存回收机制回收,比如在函数中声明的变量,会在遇到return语句或者}结束括号之后被回收。

但是在存在闭包的情况下,闭包使用的变量会被放进堆内存中,不会随着栈内存的回收而被销毁,这就形成了不销毁的变量(实际是存储在堆内存中)

不当使用会造成内存泄漏

前段时间Leader和我们谈性能优化时,特意提到了不要使用闭包,但是并没有告诉我们这些菜鸡使用闭包到底会导致什么问题。

其实问题并不是出在闭包上,而是对闭包的不良使用,上文中提到,闭包可以形成一个不销毁的栈内存,注意不销毁三个字,也就代表闭包中的变量会长期存储在内存中,如果你不主动释放它;从而导致占用内存空间,性能下降。

> 怎么做

很简单,使用结束后给变量赋值为null

参考

我从来不理解JavaScript闭包,直到有人这样向我解释它 - 掘金 (juejin.cn)

JavaScript 内存机制(前端同学进阶必备) - 掘金 (juejin.cn)