Tach!
mit button.addEventlistener('click',this.closeWindow) geht's auch nicht, weil sich "this" in dem Fall auf den Button und nicht auf das Objekt bezieht
Das this bezieht sich nur dann auf den Button wenn der Aufrufkontext, in dem der Eventhandler gesetzt wird, eine Methode des Buttons ist. Dann könnte man aber auch gleich this.addEventListener…
schreiben. Wenn der Aufrufkontext eine Methode des Windows ist, dann zeigt this
auf das Window.
Das Problem ist aber, dass zum Zeitpunkt des Events der Kontext ein anderer ist, und ein im Eventhandler verwendetes this
auf den Kontext zum Zeitpunkt des Ereignisses verweist und nicht mehr auf das Window. Die Methode wird zwar aufgerufen, aber so, als würde man sie statisch aufrufen, und nicht als Methode eines konkreten Window-Objekts.
warum speicherst du das gewünschte „this“ nicht:
dieses = this;
Button.addEventlistener('click',dieses.closeWindow);
Damit löst man das Problem nicht. Der Eventhandler bindet sozusagen nur die Adresse der Methode, aber es wird keine Closure erzeugt, die irgendwelche Daten aus dem derzeitigen Aufrufkontext festhalten würde, auf die man zum späteren Zeitpunkt des Events zugreifen könnte. Deshalb ist es egal, ob man das this
direkt schreibt oder eine Indirektion über eine weitere Variable verwendet.
Wenn sich allerdings closeWindow
im selben Scope befindet, dann bildet dieser Scope die Closure und man kann in closeWindow
auf dieses
zugreifen. Aber besser ist, den Aufruf der Arrow-Funktion aus dem nachfolgenden Beispiel zu verwenden, dann kann closeWindow
auch sonstwo definiert sein und man braucht keine Hilfsvariable.
Nehmen wir folgendes Beispiel.
<button id="foo" data-x=42>foo</button>
<button id="bar" data-x=23>bar</button>
<script>
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');
console.log(foo.dataset);
console.log(bar.dataset);
foo.clickHandler = function() {
console.log('click', this.dataset);
bar.addEventListener('click', this.clickHandler);
}
foo.addEventListener('click', foo.clickHandler);
</script>
Zwei Buttons, jeder mit einem eigenen Wert in data-x, der zur Kontrolle jeweils mit einem console.log() ausgegeben wird. Danach geben wir dem foo-Button eine neue Eigenschaft namens clickHandler
mit einer Methode als Inhalt. Und ich füge einen Eventhandler für sein Click-Ereignis hinzu. Diese Zuweisung befindet sich im globalen Kontext, this verweist auf das globale window-Objekt, deshalb muss ich foo.clickHandler übergeben.
Wenn wir auf den foo-Button klicken, ruft es den clickHandler
auf. Der Event-Mechanismus sorgt dafür, dass this
auf den foo-Button zeigt, und console.log() zeigt die 42 von foo.
Als zweite Anweisung wird dem click-Event von bar
ein Eventhandler zugewiesen. Das this
zeigt noch immer auf foo
, so wie es uns der Eventhandlermechanismus übergeben hat. Klicken wir nun auf den bar-Button, wird jetzt ebenfalls diese Methode aufgerufen. Aber die Ausgabe ist nun die 23 von bar
. Wie auch schon zuvor wurde vom Eventmechanismus das this
auf den Auslöser gesetzt, der nun bar
ist. Uns interessiert nur die console.log()-Ausgabe, die Zeile mit dem bar.addEventListener
ignorieren wir mal.
Aber für den nächsten Versuch ändern wir sie zu
bar.addEventListener('click', () => this.clickHandler());
und klicken nacheinander auf foo und bar. Beide Male wird 42 ausgegeben. Hier kommt eine Besonderheit der Arrow-Funktion zum tragen, denn diese bindet in this
den Kontext zum aktuellen Zeitpunkt, also einen Verweis auf foo
. Im Eventhandler wird die Methode clickHandler() von foo
im Kontext von foo
aufgerufen, ohne dass wir zum Eventzeitpunkt wissen müssen, dass wir uns in der Instanz von foo
befinden. Wir verwenden einfach this
.
Ändern wir zum Spaß noch die Zeile in einen Aufruf einer herkömmlichen anonymen Funktion
bar.addEventListener('click', function() { this.clickHandler(); });
bekommen wir eine Fehlermeldung beim Klick auf bar (und vorher foo)
this.clickHandler is not a function
denn nun wird als this
der Button bar
durchgereicht, der keine Methode namens clickHandler
hat.
Fazit: Arrow-Funktion verwenden. Oder was mit .bind()
zaubern, wenn modernes Javascript nicht möglich ist.
dedlfix.