Timer und Kontextverlust in JavaScript
Bei der Verwendung von Timern in Event-Handlern lauern Probleme mit Kontextverlust auf uns. Schauen wir uns ein Beispiel an.
Nehmen wir an, wir haben ein Input-Feld:
<input id="elem" value="text">
Nehmen wir an, bei einem Klick auf dieses Input-Feld wird eine anonyme Funktion ausgeführt und innerhalb dieser Funktion startet ein Timer, der jede Sekunde etwas in die Konsole ausgibt:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // geben wir etwas in die Konsole aus
}, 1000);
});
Bisher funktioniert alles korrekt. Aber nehmen wir nun an,
wir möchten den value
unseres Input-Felds in der Konsole ausgeben - uns erwartet eine Überraschung: In der Konsole
wird undefined ausgegeben:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // gibt undefined aus
}, 1000);
});
Der Grund liegt darin, dass wir eine Funktion
in einer Funktion haben: Es gibt die äußere anonyme Funktion,
die beim Klick aufgerufen wird, und die innere
anonyme Funktion, die der Timer startet.
In der äußeren Funktion zeigt this
auf das Input-Feld, aber in der inneren - nicht. Es liegt
Kontextverlust vor.
Warum wird undefined ausgegeben und erscheint kein
Fehler in der Konsole, wie in den vorherigen
Lektionen? Weil this innerhalb der Funktion,
die über setInterval aufgerufen wird, auf
window zeigt.
Das bedeutet, dass wir versuchen, die Eigenschaft
value des Objekts window auszulesen, so: window.value,
und eine solche Eigenschaft existiert darin nicht, und wir erhalten
undefined (keinen Fehler).
Korrigieren wir das Problem durch die Einführung von self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Gegeben sei dieser Code:
<input type="button" id="elem" value="1">
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
this.value = Number(elem.value) + 1;
}, 1000);
});
Der Autor des Codes wollte, dass beim Drücken der Schaltfläche
der Wert dieser Schaltfläche jede Sekunde um 1 erhöht
wird. Beim Drücken der Schaltfläche passiert jedoch
überhaupt nichts. Korrigieren Sie den Fehler
des Code-Autors. Schreiben Sie einen Text, in dem Sie
dem Autor des Codes eine Erklärung geben, warum sein Fehler
aufgetreten ist.