为了账号安全,请及时绑定邮箱和手机立即绑定

如何在一个类中删除一个事件监听器?

如何在一个类中删除一个事件监听器?

斯蒂芬大帝 2021-05-12 18:09:44
说我有以下代码: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'中引用类方法并将其传递给它一个参数。对该类的引用(例如,让this = self)不起作用,因为每次调用该函数并更改事件侦听器的签名时,都会对此类进行新版本的引用。
查看完整描述

1 回答

?
长风秋雁

TA贡献1757条经验 获得超7个赞

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


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的方法创建一个bound方法,.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

    }

}

起作用的原因是箭头函数是绑定方法的简写:


x => x + 1;


// Is functionally equivalent to:


(function(x) {

    return x + 1;

}).bind(this);

许多人没有意识到箭头函数包含隐式bind,并且对于90%的用例而言,这并不重要(例如array.map(x => x + 1),不在乎的值this),但是在类中,该简写实际上具有价值,因此成为在JavaScript类中使用箭头函数以避免覆盖this变量的相当普遍的模式。


查看完整回答
反对 回复 2021-05-27
  • 1 回答
  • 0 关注
  • 385 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信