Como posso remover um ouvinte de evento, independentemente de como o retorno de chamada é definido

Durante anos, tive problemas ao tentar remover um ouvinte de evento em JavaScript. Muitas vezes, eu teria que criar uma função independente como manipulador. Mas isso é apenas desleixado e, especialmente com a adição de funções de seta, apenas uma do

Não estou buscando uma solução ONCE. Isso precisa funcionar em todas as situações, independentemente de como o retorno de chamada é definido. E isso precisa ser JS bruto, para que qualquer pessoa possa usá-l

O código a seguir funciona bem, pois a funçãoclickHandler é uma função única e pode ser usada pelos doaddEventListener eremoveEventListener:

Este exemplo foi atualizado para mostrar o que encontrei no passado

const btnTest = document.getElementById('test');
let rel = null;

function clickHandler() {
  console.info('Clicked on test');
}

function add() {
  if (rel === null) {
    rel = btnTest.addEventListener('click', clickHandler);
  }
}

function remove() {
    btnTest.removeEventListener('click', clickHandler);
}

[...document.querySelectorAll('[cmd]')].forEach(
  el => {
    const cmd = el.getAttribute('cmd');
    if (typeof window[cmd] === 'function') {
      el.addEventListener('click', window[cmd]);
    }
  }
);
<button cmd="add">Add</button>
<button cmd="remove">Remove</button>
<button id="test">Test</button>

Você costumava fazer isso comarguments.callee:

var el = document.querySelector('#myButton');

el.addEventListener('click', function () {
  console.log('clicked');
  el.removeEventListener('click', arguments.callee); //<-- will not work
});
<button id="myButton">Click</button>

Mas a função de seta não funciona:

var el = document.querySelector('#myButton');

el.addEventListener('click', () => {
  console.log('clicked');
  el.removeEventListener('click', arguments.callee); //<-- will not work
});
<button id="myButton">Click</button>

Existe uma maneira melhor?

ATUALIZA

Conforme declarado por @Jonas Wilms desta maneira, funcionará:

 var el = document.querySelector('#myButton');

 el.addEventListener('click', function handler() {
   console.log('clicked');
   el.removeEventListener('click', handler); //<-- will work
 });
<button id="myButton">Click</button>

A não ser qu você precisa usar a ligação:

var obj = {
  setup() {
    var el = document.querySelector('#myButton');

    el.addEventListener('click', (function handler() {
      console.log('clicked', Object.keys(this));
      el.removeEventListener('click', handler); //<-- will work
    }).bind(this));
  }
}

obj.setup();
<button id="myButton">Click</button>

O problema é que existem muitas maneiras de fornecer um manipulador de eventos para oaddEventListenerunção @ e seu código pode quebrar se a maneira como você passar na função for alterada em um refato

questionAnswers(4)

yourAnswerToTheQuestion