在DOM事件回调中是否需要闭包?

时间:2012-02-19 16:02:39

标签: javascript javascript-events closures

我正在尝试构建一个类似jQuery.live的函数。 Helper是一个包含_liveEvent_addEventListener方法的类。 Helper._addEventListener只是W3C addEventListener的CrossBrowser版本。

Helper.prototype._liveEvent = function(type, evt, ofunc) {
    var elHand = document;
    type = type.toUpperCase();

    this._addEventListener(elHand, evt, function(me) {
        // Inside here I use the `type` variable.
        // I don't know why but it works.

        for (var el = me.srcElement; el.nodeName !== 'HTML';
            el = el.parentNode)
        {
            if (el.nodeName === type || el.parentNode === null) {
                break;
            }
        }
        if (el && el.nodeName === type) {
            ofunc.call(el, me);
        }

    });
};

我使用不同类型运行Helper._liveEvent功能2次。它工作得很好。我认为,由于type变量是在_liveEvent上下文中设置的,因此_addEventListener回调只能看到该变量的最后一个版本。但情况并非如此,似乎工作正常。

我的问题是:

  • 为什么_addEventListener回调可以看到该类型的两个版本?
  • 这是否意味着我的代码泄露内存?

更新

这另一个例子让我更好地理解了这一点。但是我不确定我还没看过它。

function foo(i) {
    setTimeout(function() {
        console.log(i);
    }, 400);

}

// Prints 1, 2, 3
for (var i = 1; i < 4; i++) {
    foo(i);
}

function bar() {
    for (var i = 1; i < 4; i++) {
        setTimeout(function() {
            console.log(i);
        }, 400);
    }
}

// Prints 4, 4, 4
bar();
​

2 个答案:

答案 0 :(得分:1)

实际上,您已经在创建一个闭包。这就是原因:

for( var i=0; i<10; i++) {
    elem.onclick = (function(id) {alert(id);})(i);
}

工作 - 调用匿名函数会创建一个新的闭包,id设置为{em>当前值i。 (就个人而言,我喜欢将参数称为与我想要使用的变量相同的东西,因此我可以将其视为“锁定”该函数的变量值。)

就内存泄漏而言,两次调用不会导致泄漏。如果GC以我认为的方式工作,它将删除任何没有指针的闭包。特别是,当您离开页面时,将释放与该页面关联的任何内存。

答案 1 :(得分:1)

  • 这是因为为传递给_addEventListener()的匿名函数的每个实例创建了一个单独的闭包范围,每个实例都有自己的值elHandtype
  • 这取决于你所说的“泄漏”。每个闭包都会阻止它包含GC中包含的对象。当没有更多对象(比如像您的匿名函数)引用它时,闭包是GC。从这个意义上讲,是的,您有内存泄漏,因为您无法删除添加的侦听器(匿名函数),从而使关联的范围对象符合GC的条件。