前两天和同事吹水时,突然聊到闭包,这个概念很好理解但是又感觉好像没有完全理解的东西,一直没搞懂它究竟有什么用。
概念
先来看看闭包的概念
闭包是一个函数有权访问另一个函数(另一个作用域)中声明的变量,这个函数就叫闭包。
-
优点:保存变量不受外界影响,形成不销毁的栈变量
-
缺点:不当使用会导致内存泄漏
分析
保存私有变量不被污染
不受外界影响很好理解,举栗说明:
var a = '皮皮章'
function foo() {
var a = 'foo'
function fo() {
console.log(a);
}
return fo
}
function f(p) {
var a = 'f'
p()
}
f(foo())
答案(点击后展开):
'foo'
f(foo())
实际是将fo
作为入参传递给f函数,fo
使用了在父函数foo
中声明的a
,所以即便foo函数已经执行到return
语句,变量a
仍然不会被销毁fo
函数就是一个闭包;fo
函数在f函数中被调用时,依然会使用在foo
函数中定义的a变量。
可以看到,形成闭包之后变量不会因为被重新声明赋值而受到影响,达到防止变量被污染的效果。
不销毁的栈内存
要理解不销毁的栈内存,首先要明白堆栈内存的概念,以及js内存销毁机制
- 栈内存中保存:基本类型、引用类型的指针地址
- 堆内存中保存:引用类型
通常情况,栈内存当中存储的变量,会在使用结束之后被js内存回收机制回收,比如在函数中声明的变量,会在遇到return
语句或者}
结束括号之后被回收。
但是在存在闭包的情况下,闭包使用的变量会被放进堆内存中,不会随着栈内存的回收而被销毁,这就形成了不销毁的变量(实际是存储在堆内存中)
不当使用会造成内存泄漏
前段时间Leader和我们谈性能优化时,特意提到了不要使用闭包,但是并没有告诉我们这些菜鸡使用闭包到底会导致什么问题。
其实问题并不是出在闭包上,而是对闭包的不良使用,上文中提到,闭包可以形成一个不销毁的栈内存,注意不销毁三个字,也就代表闭包中的变量会长期存储在内存中,如果你不主动释放它;从而导致占用内存空间,性能下降。
> 怎么做
很简单,使用结束后给变量赋值为null
。