¿Cómo puedo eliminar un detector de eventos sin importar cómo se defina la devolución de llamada

Durante años tuve problemas al tratar de eliminar un detector de eventos en JavaScript. A menudo tendría que crear una función independiente como manejador. Pero eso es simplemente descuidado y, especialmente con la adición de funciones de flecha, es simplemente un dolor.

No busco una solución de ONCE. Esto debe funcionar en todas las situaciones, sin importar CÓMO se defina la devolución de llamada. Y esto debe ser JS sin procesar para que cualquiera pueda usarlo.

El siguiente código funciona bien ya que la funciónclickHandler es una función única y puede ser utilizada por ambosaddEventListener yremoveEventListener:

Este ejemplo se ha actualizado para mostrar lo que me he encontrado en el pasado

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>

Solías poder hacerlo conarguments.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>

Pero usar una función de flecha no 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>

¿Hay una mejor manera?

ACTUALIZA

Como lo dijo @Jonas Wilms de esta manera 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 no ser qu necesita usar el enlace:

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>

l problema es que hay muchas maneras de proporcionar un controlador de eventos a laaddEventListener y su código podría romperse si la forma en que pasa en la función cambia en un refactor.

Respuestas a la pregunta(4)

Su respuesta a la pregunta