我正在阅读有关circular references cause memory leaks in IE的内容,但我对使用闭包内的闭包来打破循环引用的示例感到非常困惑:
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
};
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
我的头部全都与参考什么有关,哪些是闭包,哪些是范围对象。有人可以比MDN更明确地分解它吗?感谢。
答案 0 :(得分:8)
如果你有
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
// can access `el` here
};
var el = document.getElementById('el');
el.onclick = clickHandler;
}
然后el
引用了clickHandler
,但clickHandler
也引用了el
,因为它是一个闭包。 ->
循环引用(在IE中)
通过引入新范围,您可以el
本地,因此clickHandler
,->
无法访问该范围。
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
// cannot access `el` here
};
(function() {
// `el` is local to this immediately invoked function
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
因此,内存泄漏问题的解决方案是而不是引入另一个闭包,它是创建一个新范围,“屏蔽”每个值的值其他(至少在一个方向)。
答案 1 :(得分:3)
我遵循的经验法则:
对于要创建的JavaScript闭包,必须有嵌套函数,并且内部函数必须能够访问或引用外部函数中的变量(简单地说“触摸”)。如果找不到这两个条件中的任何一个,那么JavaScript中没有闭包。
当外部函数中的此类变量(在上一段中提到)碰巧是DOM元素时,就会发生内存泄漏。
在Mozilla文章中,让我们访问第一个例子:
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
};
}
显然,有一个函数嵌套在另一个函数中,并且内部函数被赋值给外部作用域中的变量( el )的属性,因此创建了一个闭包。这个变量 el 也恰好是一个DOM元素,因此存在内存泄漏,如本文所述。
在您发布的第二个示例中,
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
};
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}
有一个外部函数,嵌套在这个外部函数中是2个嵌套(内部)函数,但它们处于同一级别,这意味着一个不嵌套在另一个内部。第二个嵌套函数也可以访问外部函数中的局部变量( clickHandler ),因此会创建一个闭包。但是,没有内存泄漏,因为外部函数中的此局部变量( clickHandler )不是DOM元素。局部变量 el 不会导致内存泄漏,因为它是第二个嵌套函数的本地,而不是在外部函数 addHandler()中定义的。换句话说,它是第二个嵌套函数的本地,第一个嵌套函数无法访问它,因此没有内存泄漏的可能性。