javascript - 如何删除类中的事件监听器?

标签 javascript

假设我有以下代码:

class Sample {
    constructor() {
        this.value = 'something';
    }

    addClickListener(e) { // e is a dom element

        let func = function(e) {
             //what I want to be able to do:
             this.doThing(e);
    }

        e.addEventListener('click', func, false);
    }

    removeClickListener(e) {

        let func = function(e) {
            //what I want to be able to do:
             this.doThing(e);
        }

        e.removeEventListener('click', func, false);
    }

    doThing(p) { 
    //code
    }

}

我希望能够从“func”中引用一个类方法并向它传递一个参数。对类的引用(例如 let this = self)不起作用,因为它会在每次调用函数和事件监听器的签名更改时创建一个新版本。

最佳答案

要删除事件监听器,您需要保留对要删除的函数的引用:

class Sample {
    constructor() {
        this.value = 'something';
        // I've changed it from "let func" to "this.func" so we retain a reference
        // I also moved it from addClickListener to the constructor so that we
        // don't overwrite our reference when binding more elements to the
        // same function
        this.func = function(e) {
             //what I want to be able to do:
             this.doThing(e); // NOTE: You have another bug here. See comments
        }
    }

    addClickListener(e) { // e is a dom element
        // Replaced "func" with "this.func"
        e.addEventListener('click', this.func, false);
    }

    removeClickListener(e) {

        // Removed the new (unused) function

        // Replaced "func" with "this.func"
        e.removeEventListener('click', this.func, false);
    }

    doThing(p) { 
        //code
    }

}

注意我在评论中说“注意:你这里有另一个错误”

调用事件监听器时,上下文(this 变量)更改为发出事件的元素。所以this.doThing将尝试调用 doThing在元素上 e !

另请注意 e元素(传递给 addClickListener 的参数e 事件(传递给this.func 的参数)

要修复此错误,您需要存储对该类的引用并在您的函数定义中使用该引用:

    constructor() {
        this.value = 'something';
        let self = this;
        this.func = function(e) {
             self.doThing(e);
        }
    }

在这里self不会this那样被覆盖将,所以我们可以安全地使用它来引用类实例

更好的解决方案

当我重新阅读这个问题时,我意识到你的函数实际上只是在调用另一个函数。因此,为什么不将最终要运行的功能传递给addEventListener呢? ?

class Sample {
    constructor() {
        this.value = 'something';
    }

    addClickListener(e) {
        e.addEventListener('click', this.doThing, false);
    }

    removeClickListener(e) {
        e.removeEventListener('click', this.doThing, false);
    }

    doThing(p) { 
        //code
    }
}

请注意,这仍然会有 this 的问题被调用事件的元素替换,所以在 doThing 内你不能说 this.doOtherThing调用第二类方法。如果您希望这样做,则需要使用 JavaScript 的 .bind() 创建一个绑定(bind)方法像这样的方法:

class Sample {
    constructor() {
        this.value = 'something';
        this.boundMethod = this.doThing.bind(this);
    }

    addClickListener(e) {
        e.addEventListener('click', this.boundMethod, false);
    }

    removeClickListener(e) {
        e.removeEventListener('click', this.boundMethod, false);
    }

    doThing(p) {
        //code
        this.doOtherThing(p);
        //more code
    }

    doOtherThing(p) {
        //code
    }
}

另一种选择

正如@evolutionxbox 所指出的,您也可以使用箭头函数。这个解决方案看起来像这样:

class Sample {
    constructor() {
        this.value = 'something';
        this.boundMethod = p => { this.doThing(p); };
    }

    addClickListener(e) {
        e.addEventListener('click', this.boundMethod, false);
    }

    removeClickListener(e) {
        e.removeEventListener('click', this.boundMethod, false);
    }

    doThing(p) {
        //code
        this.doOtherThing(p);
        //more code
    }

    doOtherThing(p) {
        //code
    }
}

这样做的原因是箭头函数是绑定(bind)方法的简写:

x => x + 1;

// Is functionally equivalent to:

(function(x) {
    return x + 1;
}).bind(this);

很多人没有意识到箭头函数包含隐式的 bind ,并且对于 90% 的用例来说,这无关紧要(例如 array.map(x => x + 1) 不关心 this 的值)但是在类中这个简写实际上是有值(value)的,所以它已经成为一个相当普遍的模式在 JavaScript 类中使用箭头函数以避免覆盖 this变量。

关于javascript - 如何删除类中的事件监听器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56079864/

相关文章:

javascript - Accordion 切换不更改 Bootstrap 3 中的图标

CSS 样式上的 Javascript 事件从 block 更改为无

javascript - WordPress 主题 : add custom scripts and jquery the correct way

javascript - 更改 JavaScript 中的局部变量会影响具有不同名称的原始全局变量

javascript - 如何使用 Node js 中的 xlsx/sheetjs 包在现有 xlsx 文件中创建新工作表?

javascript - 如何在自定义javascript对象中设置标签onclick?

javascript - Wordpress - style.css 似乎没有在 Chrome 上更新

javascript - 是否可以使用 Angular HTML 文档进行 $compile

javascript - 可滚动的图片库循环在最后一张图片之后工作,它应该再次从第一张图片开始

javascript - 这是 NodeJS 中的变量作用域错误还是我只是需要更多的 sleep