首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议155:小心闭包导致内存泄漏

关灯直达底部

闭包是JavaScript最强大的一个方面,它允许函数访问局部范围之外的数据。在复杂的网页应用中闭包无处不在。有一种性能影响与闭包有关。为了分析与闭包有关的性能问题,考虑下面的例子:


function assignEvents{

var;

document.getElementById("save-btn").onclick=function(event){

saveDocument(id);

};

}


assignEvents函数为一个DOM元素指定了一个事件处理句柄。此事件处理句柄是一个闭包,当assignEvents被执行时,可以访问其范围内部的id变量。要用这种方法封闭对id变量的访问,必须创建一个特定的作用域链。

当assignEvents被执行时,一个激活对象被创建,其中包含了一些应有的内容,比如id变量,它将成为运行期上下文作用域链上的第一个对象,全局对象是第二个。当闭包被创建时,scope属性与这些对象一起被初始化。

由于闭包的scope属性包含与运行期上下文作用域链相同的对象引用,因此会产生副作用。通常,一个函数的激活对象与运行期上下文一同被销毁。当涉及闭包时,激活对象就无法被销毁了,因为引用仍然存在于闭包的scope属性中。这意味着与脚本中的非闭包函数相比,闭包需要更多内存开销。在大型网页应用中,这可能是个问题,尤其在IE中更被关注。IE使用非本地JavaScript对象实现DOM对象,闭包可能导致内存泄漏。

当闭包被执行时,一个运行期上下文将被创建,它的作用域链与在scope中引用的两个相同的作用域链同时被初始化,然后一个新的激活对象作为闭包自身被创建。

注意,在闭包中使用的两个标识符:id和saveDocument,它们存在于作用域链第一个对象之后的位置上。这是闭包最主要的性能关注点:经常访问一些范围之外的标识符,每次访问都导致一些性能损失。

在脚本中最好小心地使用闭包,内存和运行速度都值得去关注。但是,可以将常用的域外变量存入局部变量中,然后直接访问局部变量,这样能够减小对运行速度的影响。