Časovače a ztráta kontextu v JavaScriptu
Při použití časovačů v obslužných funkcích událostí na nás číhají problémy se ztrátou kontextu. Podívejme se na příklad.
Předpokládejme, že máme vstupní pole:
<input id="elem" value="text">
Předpokládejme, že po kliknutí na toto vstupní pole se spustí anonymní funkce a uvnitř této funkce se spustí časovač, který každou sekundu vypíše něco do konzole:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // něco vypíšeme do konzole
}, 1000);
});
Zatím vše funguje správně. Ale nyní předpokládejme,
že chceme do konzole vypsat value
našeho vstupního pole - čeká nás překvapení: do konzole
se bude vypisovat undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // bude se vypisovat undefined
}, 1000);
});
Jde o to, že máme funkci
ve funkci: existuje vnější anonymní funkce,
která je volána po kliknutí, a vnitřní
anonymní funkce, kterou spouští časovač.
Ve vnější funkci this ukazuje
na vstupní pole, ale ve vnitřní - ne. Dochází
ke ztrátě kontextu.
Proč se vypisuje undefined, a neobjeví se
chyba v konzoli, jako tomu bylo v předchozích
lekcích? Protože this uvnitř funkce,
volané přes setInterval, ukazuje
na window.
To znamená, že se snažíme přečíst vlastnost
value u objektu window, takto: window.value,
a taková vlastnost v něm není, a dostáváme
undefined (ne chybu).
Problém opravíme zavedením self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Předpokládejme, že je dán takový kód:
<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 kódu chtěl, aby se po stisknutí tlačítka
hodnota tohoto tlačítka každou sekundu zvyšovala
o 1. Avšak po stisknutí tlačítka
se nic neděje. Opravte chybu
autora kódu. Napište text, ve kterém
poskytnete autorovi kódu vysvětlení, proč k jeho
chybě došlo.