JQuery事件是否会在销毁到哪里时自动解除绑定?

时间:2010-06-22 18:32:16

标签: javascript jquery javascript-events

如果我在对象的两个函数中有以下代码:

add: function()
{
    // create trip.
    var trip = new Trip();

    // add the trip using its id.
    this.trips[trip.id] = trip;
},

remove: function(tripId)
{
    // remove trip.
    delete this.trips[tripId];
}

注意:Trip对象的构造函数将一堆自定义JQuery事件处理程序绑定到自身。

删除Trip对象时,是否会自动销毁/清除绑定到Trip对象的事件处理程序?

如果dom节点被移除并且绑定了事件处理程序,那么同样会发生吗?

此外,我读到垃圾收集器不会清除对象,直到对它们的所有引用都不再存在,因此绑定到该对象的事件处理程序本身作为引用计数并防止对象被清除,即使我不再引用它了吗?

3 个答案:

答案 0 :(得分:5)

该事件不会被删除,因为jQuery维护所有绑定事件处理程序的中央存储库,并且确实知道是否或何时使用delete删除了关联对象。尝试这个小测试来确认。 (仅限jQuery 1.4.2)

jsfiddle link

// 1. a regular JS object
var root = {};
// Since we can't delete anything created with var (except on Chrome),
// we use an object property here. An array value works just as well,
// which is already the case in your example.
root.o = {};

// 2. at this point, jQuery creates an internal property
// jQuery<UNIQ_ID>, for example jQuery1277242840125 inside object o
$(root.o).bind("myEvent", function() { alert("here"); });

// 3. get the *internal* index jQuery assigned this object:
// there's only 1 property, so we just enumerate and fetch it.
var internalIndex;
for(var prop in root.o) {
    internalIndex = root.o[prop];
}

// 4. delete the object
delete root.o;

// 5. query jQuery internal cache with the internal index from step 3
console.log(jQuery.cache[internalIndex].events);
​

步骤5应记录与ex-o对象关联的所有事件类型的数组,包括“myEvent”,以及它的关联处理程序,因此不会自动删除绑定事件处理程序。这是我看到的记录(剥离不相关的属性):

▾ Object
  ▾ myEvent: Array (1)
    ▾ 0: Object
      ▸ handler: function () { alert("here"); }
        namespace: ""
        type: "myEvent"
      length: 1

但是,对象删除不受影响,并且将按预期删除。然而,由于jQuery的缓存中存在关联数据,因此它仍然存在于墙壁中的一个漏洞。

虽然您可以将事件绑定到纯JavaScript对象,但您无法取消绑定它们。看来jQuery假定在解除绑定时对象是一个DOM节点,并抛出以下错误:

Uncaught TypeError: Object #<an Object> has no method 'removeEventListener'

我认为,即使是能够将事件绑定到对象的部分也没有记录。因此,您必须对此有点小心,因为在尝试清理该对象的事件处理程序引用时,以下操作无效:

<击>

<击>
$(object).remove()
$(object).unbind(..)

<击>

作为一种解决方法,在清理Trip对象时,您可以明确地调用removeData来完成这项工作。

$(object).removeData();

正如我已经提到过的那样,jQuery的内部问题越来越深入,所以你可能想看一个替代解决方案,或者担心库升级很容易破坏你的代码,这不太可能。

答案 1 :(得分:0)

据我所知,您只能将事件处理程序绑定到节点,或者在特殊情况下绑定窗口,文档等。对于DOM节点,将删除事件处理程序。即使他们不是,他们也无法被触发。删除对象将删除与其关联的事件处理程序。事件处理程序不应该阻止对象被垃圾回收。

答案 2 :(得分:0)

  

如果dom节点发生同样的情况   它被删除并有事件处理程序   绑定它?

this.handlerClick = function () { ... };

$(this.testDomNode).bind('click', this.handlerClick);

this.testDomNode.parentNode.removeChild(this.testDomNode);

使用上面的代码并在FireFox中使用FireQuery进行测试,删除dom节点并不会解除事件中的处理程序,

似乎你必须在删除dom节点之前显式取消绑定处理程序,如下所示:

$(this.testDomNode).unbind('click', this.handlerClick);

this.testDomNode.parentNode.removeChild(this.testDomNode);