具有 JavaScript 个事件函数闭包的可变生命

Variable life with JavaScript function closures for events

如果我在函数中将匿名函数分配给元素的事件,那么该事件将可以访问函数的“环境”,即使在函数完成后也是如此。

如果我更改元素的事件函数会怎样?之前的“环境”是否被垃圾收集或仍在内存中?

或者如果我从 DOM 中删除该元素会怎样?

function blah(div)
{
    var a = 1;
    div.onclick = function(){ alert(a); }; // this alerts 1 as expected because a is in the "environment" of the onclick function
}

blah(someElement);

// somewhere else
someElement.onclick = function()
{
    // i know a is inaccessible here but what happened to it? is it still in memory somewhere?
}

// and what about here?
someElement.parentNode.removeChild(someElement);

Note:

You will want to avoid attaching js objects to a dom node. It will use more memory and will have to be removed individually. A much better way would be to create a js object and then reference the dom node. As always remember to clean up the js objects/events first before removing the dom nodes. Javascript's Garbage Collector is able to detect circular references and handle them correctly, but the DOM's Garbage Collector can not.

这个 post 描述了那个案例:https://www.interworks.com/blog/mgardner/2009/08/31/avoiding-memory-leaks-and-javascript-best-practices

Referencing a variable outside the scope of a DOM element's event function (formally known as a closure see http://www.jibbering.com/faq/faq_notes/closures.html for more information). The problem is that the variable and function become intertwined due to the reference and will not be collected unless both are freed (won't happen until page unload for global variable references). If the event is never removed/released the garbage collector will never collect both the object and the DOM fully.

会泄漏示例:

var bigString = new Array(1000).join(new Array(2000).join("XXXXX")); 
var d = document.createElement("div");
d.onclick = function() {
   this.innerHTML = bigString.length;
};
document.body.appendChild(d);
d.parentNode.removeChild(d);

不会泄漏示例:

var bigString = new Array(1000).join(new Array(2000).join("XXXXX")); 
var d = document.createElement("div");
d.onclick = function() {
  this.innerHTML = bigString.length;
};
document.body.appendChild(d);
bigString = null;
d.onclick = null;
d.parentNode.removeChild(d);