闭包是什么?
闭包: 是指有权访问另一个函数作用域中的变量的函数。
闭包无处不在,比如 jQuery 、zepto 的核心代码都包含在一个大的闭包中。
先来看一个闭包 ⬇️ ⬇️ ⬇️
闭包的用途
闭包的实现原理,其实是利用了作用域链的特性。
我们都知道作用域链就是在当前执行环境下访问某个变量时,如果不存在就向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。
隐藏变量,避免污染
在 Javascript 中,如果一个对象不再被引用,那么这个对象就会被 GC 回收,否则这个对象一直会保存在内存中。
上面的代码,当函数 outSide
被执行后返回了函数 inSide
,函数inSide
的作用域链上有引用到函数 outSide
执行环境的变量 a
,这个变量会被函数 fn
引用,所以 a
不会被垃圾回收机制处理掉,而是会留在内存中。这就形成了一个闭包。最后执行 fn()
依然能读取到变量 a
。
而如果不用闭包的话 ⬇️ ⬇️ ⬇️
如果我们再次调用 inSide()
时,结果会一直增加,相应的全局变量 a
的值一直递增。
如果其他函数也需要使用这个变量 a
,那么 inSide
函数会改变 a
的值,使其他地方出错。而且全局变量容易被人修改,比较不安全。
所以,当我们需要在模块中定义一些变量,并希望这些变量一直保存在内存中但又不会 “污染” 全局的变量时,就可以用闭包来定义这个模块。
闭包的缺点
所以如果闭包使用不当,优点就变成了缺点
- 错误地使用闭包,导致无用的变量不会被垃圾回收机制回收,造成内存消耗;
- 过多/不恰当地使用闭包可能会造成内存泄漏的问题。
闭包应用对比
假如要对用户的某个数据实现一个自增需求,但又不能改变该用户本身的数据。
- 定义全局变量可以实现,但是会改变本身的
age
- 定义局部变量,但实现不了递增
- 闭包可以实现递增并且不污染全局变量