销毁 JavaScript 中的对象及其绑定

Destroy objects and their bindings in JavaScript

本文关键字:绑定 对象 JavaScript 销毁      更新时间:2023-09-26

我在 JavaScript 中有这个类:

(function() {
    this.testObject = function() {
        /*options*/
        this.options = arguments[0];
    };
    /*make object*/
    testObject.prototype.make = function(){
        this.targetElement = document.getElementById('testDiv');
        this.targetElement.addEventListener('mousedown', function(e){
            ...
        });
        this.targetElement.addEventListener('mouseup', function(e){
            ...
        });
        this.targetElement.addEventListener('mousemove', function(e){
            ...
        });
    };
}());
var test; // I need this to be global
function callObject(){
    test = new testObject({...});
    test.make();
}

此对象绑定一些事件。 实例化也在另一个函数中。 这是因为我遇到向 DOM 添加新元素的情况,因此为每个新元素调用 callObject() 来为其绑定事件。

但我认为这里有一个性能问题,当我多次打电话callObject时,它会变慢。我不知道实际上是什么问题。

那么如何删除对象及其所有绑定事件呢?

> var test; // I need this to be global
> function callObject(){
>     test = new testObject({...});
>     test.make();
> }

在上面,test 将只引用 testObject 的最后一个实例。

您使用的模式意味着原型链上的每个函数都有一个对外部 IIFE 的执行上下文的闭包,make 方法添加的每个侦听器也是如此。如果您不需要闭包,这是低效的。如果不是,那么在这里使用 IIFE 是不合适的,请考虑使用标准方法(约定为构造函数提供一个以大写字母开头的名称):

function TestObject() {
    /*options*/
    this.options = arguments[0];
}
TestObject.prototype.make = function (){
    this.targetElement = document.getElementById('testDiv');
    this.targetElement.addEventListener('mousedown', function (e){
        ...
    };
    this.targetElement.addEventListener('mouseup', function (e){
        ...
    };
    ...
};

如其他地方所述,使用函数表达式添加侦听器使得以后很难删除它们。上述模式还意味着每个实例都有自己的函数副本。解决这两个问题的替代方法是使用引用。您可以将它们添加为构造函数的属性,这样它们就不会创建额外的全局变量,也不需要另一个对象,例如

TestObject.mousedown = function (e){ ... };
TestObject.mouseup   = function (e){ ... };
TestObject.prototype.make = function(){
    var TO = TestObject;
    this.targetElement = document.getElementById('testDiv');
    this.targetElement.addEventListener('mousedown', TO.mousedown, false);
    this.targetElement.addEventListener('mouseup',  TO.mouseup, false);
    ...
};

这避免了大量的闭包和不必要的函数副本,并意味着可以按名称删除侦听器。您可能希望使测试全局为对象或数组,以便可以保留对 TestObject 的所有实例的引用,而不仅仅是最后一个实例。

有几件事需要考虑。首先,也是最重要的,事件侦听器具有匿名函数。当您为侦听器提供 anon 函数时,您无法取消绑定侦听器。因此,请继续为这些制作实际功能。然后,您可以像调用addEvent...相同的方式调用removeEventListener,它将分离这些侦听器。

我通常做的是创建一个destroy函数,该函数删除所有侦听器并将任何全局变量设置为null。然后,您可以在需要时调用该销毁函数。