Timery i utrata kontekstu w JavaScript
Przy użyciu timerów w procedurach obsługi zdarzeń czekają na nas problemy z utratą kontekstu. Spójrzmy na przykład.
Załóżmy, że mamy pole input:
<input id="elem" value="text">
Załóżmy, że po kliknięciu na to pole input uruchomi się anonimowa funkcja i wewnątrz tej funkcji wystartuje timer, który co sekundę wypisze coś w konsoli:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // coś wypisujemy w konsoli
}, 1000);
});
Na razie wszystko działa poprawnie. Ale załóżmy teraz, że
chcemy wypisać w konsoli value
naszego pola input - czeka nas niespodzianka: w konsoli
będzie wypisywane undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // będzie wypisywane undefined
}, 1000);
});
Chodzi o to, że otrzymujemy funkcję
w funkcji: jest zewnętrzna funkcja anonimowa,
która jest wywoływana po kliknięciu i wewnętrzna
funkcja anonimowa, którą uruchamia timer.
W funkcji zewnętrznej this wskazuje
na pole input, ale we wewnętrznej - nie. Mamy do czynienia
z utratą kontekstu.
Dlaczego wypisywane jest undefined, a nie wyskakuje
błąd w konsoli, jak to miało miejsce w poprzednich
lekcjach? Ponieważ this wewnątrz funkcji,
wywoływanej przez setInterval, wskazuje
na window.
Oznacza to, że próbujemy odczytać właściwość
value obiektu window, tak o: window.value,
a takiej właściwości w nim nie ma i otrzymujemy
undefined (nie błąd).
Poprawmy problem wprowadzając self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Załóżmy, że dany jest taki kod:
<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);
});
Autor kodu chciał, aby po naciśnięciu przycisku,
wartość tego przycisku co sekundę zwiększała się
o 1. Jednak po naciśnięciu przycisku
nic się nie dzieje. Popraw błąd
autora kodu. Napisz tekst, w którym
dasz wyjaśnienie autorowi kodu, dlaczego powstał
jego błąd.