Theo der Kaffee: removeEventListener mit bind

Hallo,

kurze Frage:

Ich habe einen Button mit einem EventListener, den ich irgendwann im Code wieder entfernen möchte. Das funktioniert auch, solange ich nicht mit bind Elemente anhänge, siehe wie folgt:

let btn = document.getElementById("btn");
let Func = (e) => {
	e.preventDefault();
	console.log("Funktion wird aufgerufen!");
};
// btn.addEventListener("click", Func); // mit dieser Zeile würde removeEventListener "greifen"
btn.addEventListener("click", Func.bind(this)); // hier "greift" removeEventListener nicht, console.log("Funktion wird aufgerufen!") wird nach wie vor aufgerufen

btn.removeEventListener("click", Func);

Warum wird hier also trotz removeEventListener die Funktion Func noch aufgerufen?

Danke Theo.

  1. @@Theo der Kaffee

    let btn = document.getElementById("btn");
    let Func = (e) => {
    	e.preventDefault();
    	console.log("Funktion wird aufgerufen!");
    };
    // btn.addEventListener("click", Func); // mit dieser Zeile würde removeEventListener "greifen"
    btn.addEventListener("click", Func.bind(this)); // hier "greift" removeEventListener nicht, console.log("Funktion wird aufgerufen!") wird nach wie vor aufgerufen
    
    btn.removeEventListener("click", Func);
    

    Warum wird hier also trotz removeEventListener die Funktion Func noch aufgerufen?

    “The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process.” [MDN]

    Wenn die event listener function nicht matcht, wird der EventListener nicht entfernt.

    🖖 Stay hard! Stay hungry! Stay alive! Stay home!

    --
    “Turn off CSS. If the page makes no sense, fix your markup.” —fantasai
    1. Wieso matcht die Funktion nicht, bzw. wie bringe ich sie dazu, zu matchen?


      Auch

      btn.removeEventListener("click", Func.bind(this));
      

      funktioniert nicht, obwohl die Funktion doch ident mit der Funktion sein sollte, die zuvor angehängt wurde (this bezieht sich in diesem BSP in beiden Fällen auch auf dasselbe, nämlich das Window Objekt)

      1. Hallo Theo,

        nein. Jeder bind erzeugt eine neue gebundene Funktion.

        let a = Func.bind(this);
        let b = Func.bind(this);
        
        console.log(a == b);  // false;
        

        Wenn Du einen mit bind erzeugten Eventhandler entfernen willst, musst Du das Ergebnis von Func.bind speichern und beim remove den gespeicherten Wert angeben.

        Oder du musst das this anders in die Funktion hineinbugsieren. Closures sind ein sehr mächtiges Werkzeug in JavaScript und können Dir hier helfen. Für das "wie" müsste man mehr über deine Programmstruktur wissen.

        Ich habe gerade keine Lust es auszuprobieren. Aber soweit ich mich erinnere, haben Arrowfunktionen ein transparentes this, d.h. sie bekommen beim Aufruf kein eigenes this sondern verwenden das aus dem Kontext, wo sie definiert wurden. Demnach wäre der .bind möglicherweise nicht nötig.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. let a = Func.bind(this);
          let b = Func.bind(this);
          
          console.log(a == b);  // false;
          

          ...macht tatsächlich durchaus Sinn!

          Wenn ich daher die Funktion und ihre Argumente in einer Variable also zwischenspeichere, kann ich sie mit removeEventListener dann auch referenzieren, frei nach dem Motto

          let Zwischenspeicher = Func.bind(this); // oder auch mehrere Argumente à la Func.bind(this, foo, bar)
          
          btn.addEventListener("click", Zwischenspeicher); 
          btn.removeEventListener("click",  Zwischenspeicher);
          

          Wäre das ein vertretbarer Ansatz?

          1. Hallo Theo,

            Wäre das ein vertretbarer Ansatz?

            Wenn das zum Rest deines Programms passt, sicher.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Danke Gunnar und speziell Rolf für die späte Hilfe!

              Kipp zum Wochenausklang ein kühles Blondes auf euch, MUSS sein