闭包概念
闭包是 js 的一种特性,只要用 js 函数式编程,就一定会触及到闭包,而闭包的形成与作用域以及变量的生命周期有关。
参考 javascript设计模式与开发实践。[^1]
为什么形成闭包
形成闭包的条件:在一个函数作用域中去访问另一个函数的变量
- 例如
function a() { var x = 1 return function() { console.log(x++) } } let aFun = a() aFun() // 1 aFun() // 2 aFun() // 3
- 上述所述,在函数 a 中声明了一个局部变量 x ,在其内部 return 的函数中访问了函数 a 中的 x 变量,此时发现变量 x 还在某处被使用,这个变量就没有被销毁的理由,就会形成闭包结构,变量的生命周期被延续,所以一直调用 aFun() 变量 x 也会在上一次的基础上++。
内存泄露
闭包很强大,使用非常广泛,但人们对它似乎有误解,一种说法是,闭包会造成内存泄露,所以要尽量减少闭包
- 局部变量本应该随着函数销毁而销毁,但是却因为有某处在使用它,被封闭在了内存中形成闭包环境,从这个意义来说确实会使变量无法及时释放,但这里不能被说是内存泄露。如果需要回收这些变量,手动设为 null 即可。
- 和内存泄露有关的地方是,闭包循环引用,如果闭包的作用域链中保存着一些 DOM 节点,这时候就有可能造成内存泄露,但这不是闭包和javaScript的原因,在 IE 浏览器中 BOM 和 DOM 中的对象使用 C++ 以 COM 对象实现的,而 COM 对象垃圾回收机制采用的为 计数策略 ,在这种机制下,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但这不是闭包造成的。
- 同理,如果要解决内存泄露,需要手动将其设为 null,设 null 后意味着切断变量与它之前引用值之间的连接,当垃圾回收机制下次运行时,就会删除这些值并回收内存。