无法移除 eventListener,试了 6 小时

Can't remove eventListener, tried for 6 hours

我已经尝试了几个小时删除事件侦听器,但没有成功。

由于我进行了测试,我了解到问题可能出在听众参考上。

这是代码。为了清晰起见,我剥离并简化了所有内容。

    const COMPLETE = 'complete';
    let dispatcher = new EventTarget;

    class Template {
        complete(e){
            e.currentTarget.removeEventListener(COMPLETE, this.complete);
            console.log('I run only once');
        }
    }

    let child = new Template();
    child.exe = function(){
        dispatcher.addEventListener(COMPLETE, this.complete.bind(this));
    }
    child.exe();


    
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));

当然在控制台中你可以读三遍“I 运行 only once”。

我所做的测试涉及额外的变量 'functionReference',我在其中存储侦听器引用。然后就可以了。

    let functionReference
    const COMPLETE = 'complete';

    let dispatcher = new EventTarget;

    class Template {
        complete(e){
            e.currentTarget.removeEventListener(COMPLETE, functionReference);
            console.log('i run only once');
        }
    }

    let child = new Template();
    child.exe = function(){
        functionReference = this.complete.bind(this);
        dispatcher.addEventListener(COMPLETE, functionReference);
    }
    child.exe();


    
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));

现在在控制台中只有一次“我 运行 只有一次”。

这是怎么回事?为什么我不能删除那个监听器?

***** 下面的更新/解决方案 ***非常感谢 Teemu 和 amrender singh


谢谢 amrender singh 的解释! 并感谢你 Teemu 的好主意和解决方案! 非常感谢您的快速帮助!好多年没这么卡了

下面的 Teemu 解决方案:

const COMPLETE = 'complete';
let dispatcher = new EventTarget;

class Template {
    constructor(){
        this.complete = (e)=>{
            e.currentTarget.removeEventListener(COMPLETE, this.complete);
            console.log('i run only once');
        }
    }
}

let child = new Template();
child.exe = function(){
    dispatcher.addEventListener(COMPLETE, this.complete);
}
child.exe();



dispatcher.dispatchEvent(new Event(COMPLETE));
dispatcher.dispatchEvent(new Event(COMPLETE));
dispatcher.dispatchEvent(new Event(COMPLETE));

或者,可以存储对侦听器的引用并将其作为变量传递。

来自 MDN:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

在第一个例子中:

dispatcher.addEventListener(COMPLETE, this.complete.bind(this));

绑定创建一个新函数并将其附加为处理程序。这就是为什么您无法删除事件侦听器,因为您之前使用 bind 附加的事件侦听器与您的完整方法不同。

在你的第二个例子中:

functionReference = this.complete.bind(this);
dispatcher.addEventListener(COMPLETE, functionReference);

您正在将 bind 返回的新函数注册为侦听器,然后将其删除,因为在两个 add/remove 中侦听器是相同的,这就是它被删除的原因。