Aufrufende Variable im Objekt ermitteln
bearbeitet von dedlfixTach!
> > 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:
>
> ~~~ JavaScript
> 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.
```html
<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
```js
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
```js
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, aber das ist semantisch
dedlfix.