为什么Internet Explorer 8中会出现这种情况?

jor*_*aul 11 javascript internet-explorer memory-leaks

为什么以下代码泄漏?

for (var i = 0; i < 100; i++) {
    var item = {};
    item.elem = document.createElement('div');
    document.body.appendChild(item.elem);
    item.addEvent = function(name,listener) {
        var self = this;
        var wrappedListener = function() {
            return listener.apply(self,arguments);
        }
        //Uh-oh creating a circular reference here!
        //The wrappedListener has a closure on self and therefore on item.elem.
        addEvent(this.elem,name,wrappedListener);
        return wrappedListener;
    }
    var wrap = item.addEvent('eventName',listen);

    //Now remove the eventHandler - this should free up the circular reference.
    removeEvent(item.elem, 'eventName', wrap);
    if (item.elem.parentNode) {
        item.elem.parentNode.removeChild(item.elem);
    }
    //item.elem = null; //With this also un-commented, the leak disappears.
    //The fact that I have to null item.elem tells me that something is holding
    //a reference to item, and therefore elem. Setting elem to null fixes the
    //problem, but since I am removing the event handler, I don't think this
    //should be required.
}
Run Code Online (Sandbox Code Playgroud)

注:addEventremoveEvent只是抽象attachEvent/ addEventListenerInternet Explorer和其他浏览器之间的差异.

我创建了一个jsFiddle项目来演示这个问题.只需启动Internet Explorer 8并在任务管理器或Process Explorer中查看它.此外,您将看到addEventremoveEvent那里的定义.

http://jsfiddle.net/rJ8x5/34/

编辑:嗯,我提出了以下解决方案.它不漂亮,但它的工作原理! http://jsfiddle.net/rJ8x5/43/

var item = {};
item.elem = document.createElement('div');
document.body.appendChild(item.elem);
item.addEvent = function(name,listener) {
    var wrappedListener = function() {
        //Access the scope through the callee properties.
        return listener.apply( arguments.callee.scope, arguments);
    }
    addEvent(this.elem,name,wrappedListener);
    //Save the scope not as a closure, but as a property on the handler.
    wrappedListener.scope = this
    return wrappedListener;
}
var wrap = item.addEvent('eventName',listen);
removeEvent(item.elem, 'eventName', wrap);
//Force the circular reference to GO AWAY.
wrap.scope = null
if (item.elem.parentNode) {
    item.elem.parentNode.removeChild(item.elem);
}
//item.elem = null; //No longer needed.
Run Code Online (Sandbox Code Playgroud)

Mar*_*sen 5

问题是事件(几乎总是在Internet Explorer中,BTW).

看看http://jsfiddle.net/rJ8x5/39/并注意垃圾如何收集罚款.

附加事件时,您正在创建循环引用.阅读更多相关信息在HTML页面上对DOM对象的循环引用会导致内存泄漏.