闭包
闭包的本质就是在一个函数内部创建另一个函数。闭包的三个特性:
- 函数嵌套函数
- 函数内部可以引用函数外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
为什么闭包可以延长变量的生命周期?
闭包在函数定义时就已经产生, 函数存在对外部作用域的引用, 外部函数执行完由于还有作用域被引用, 因此垃圾不会回收被引用的部分。
回调函数一般都会产生闭包,因为其接收的参数为外部函数的作用域里的变量
应用
- 封装变量:把不需要暴露在全局的变量封装成“私有变量”
// 一般借助立即执行函数, 执行时返回的函数作为可供调用的接口
// 该函数中已经引用了外部作用域
// 而外部作用域在立即执行函数执行结束后已经被垃圾回收了, 仅保存了闭包作用域
// 达到了保护私有变量的要求
var moduel = (
function(){
var number = 0 // 被保护的私有变量
// 暴露出去的接口, 调用一次就会增加一次私有变量的值
return function(){
number++
}
}
)()
- 延续局部变量的寿命
var report = (function(){
var imgs = [];
return function( src ){
var img = new Image();
imgs.push( img );
img.src = src;
}
})();
report( 'http://xxx.com/getUserInfo' );
缺点:
闭包会导致变量常驻内存, 如果不及时清理掉, 会使一些数据无法被及时销毁。我们使用闭包的一部分原因是我们选择主动把一些变量封闭在闭包中,因为可能在以后还需使用这些变量,把这些变量放在闭包中和放在全局作用域,对内存方面的影响是一致的,但这里不能说成是内存泄露。如果在将来需要回收这些变量,我们可以手动把这些变量设为 null。
闭包会造成内存泄露么?
跟闭包和内存泄露有关系的地方是,使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些DOM节点,这时候就有可能造成内存泄露,但这并非闭包的问题,也并非avaScript的问题。在 IE 浏览器中,由于 BOM 和 DOM 中的对象是使用 C++以 COM 对象的方式实现的,而 COM 对象的垃圾收集机制采用的是引用计数策略。在基于引用计数策略的垃圾回收机制中,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的。