删除 JavaScript 类 中的嵌套事件侦听器

Remove nested event listeners in JavaScript classes

我有一个事件监听器,它是由 class 中的函数添加的另一个事件监听器添加的。我希望这个事件侦听器执行一次然后自行删除。

为简化问题,假设我有以下 HTML 代码:

<div class="container">
<div class="redDiv">some html</div>
<div class="blueDiv">some html</div>
</div>

和以下 JavaScript 代码:

class Test {

    constructor(_container){
      this.container = _container;
    }

    somefunc(){
      // some code here
      this.removeEventListener('click',somefunc);
    }

    start(){
      var container = this.container;    
      container.querySelector('.redDiv').addEventListener('click',function(){
        container.querySelector('.blueDiv').addEventListener('click',somefunc);
      });
    } 
  }



let tester = new Test(document.querySelector('.container'));
tester.start();

我遇到的第一个问题是 somefunc 没有在第二个事件监听器的范围内定义。我找到的唯一解决方案是在 start 函数中创建一个新变量 fnc 并将 somefunc 赋值给它,然后调用 fnc 而不是 somefunc

这使得添加事件侦听器和代码 运行 如预期的那样,但是当 somefunc() 被执行时,删除事件侦听器不起作用,因为 somefunc 在这个范围。

我试图通过将代码更改为以下内容来将 somefunc 传递给此范围:

class Test {

    constructor(_container){
      this.container = _container;
    }

    somefunc(func){
      return function(){
      // some code here
      this.removeEventListener('click',func);
      }
    }


    start(){
      var fnc = this.somefunc;
      var container = this.container;    
      container.querySelector('.redDiv').addEventListener('click',function(){
        container.querySelector('.blueDiv').addEventListener('click',fnc(fnc));
      });
    } 
  }

let tester = new Test(document.querySelector('.container'));
tester.start();

现在,代码不会生成任何错误,但事件侦听器未按需要删除。这可能与 JavaScript 分配变量的方式有关,这是我不太了解的主题。但我感兴趣的是如何解决这个问题,并能够在事件侦听器执行后将其删除。

一个解决方案是使用 arrow function 来维护 this 的引用...

class Test {

    constructor(_container){
      this.container = _container;
    }

    somefunc(fn){
      console.log('clicked blue div')
      this.container.querySelector('.blueDiv').removeEventListener('click', fn);
    }


    start(){
      var container = this.container;    
      container.querySelector('.redDiv').addEventListener('click',() => {
        console.log('clicked red div')
        // Wrap someFunc in an arrow function to have "this" inside somefunc 
        // reference this class. 
        const func = () => this.somefunc(func);
        container.querySelector('.blueDiv').addEventListener('click', func);
      });
    } 
  }

let tester = new Test(document.querySelector('.container'));
tester.start();

StackBlitz Example