Tajmeri i gubitak konteksta u JavaScript
Pri korišćenju tajmera u rukivaocima događaja čekaju nas problemi sa gubitkom konteksta. Pogledajmo na primeru.
Neka imamo input:
<input id="elem" value="text">
Neka klik na ovaj input pokrene anonimnu funkciju i unutar te funkcije pokrene se tajmer, koji svake sekunde ispisuje nešto u konzolu:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // nešto ispisujemo u konzolu
}, 1000);
});
Za sada sve radi kako treba. Ali neka sada
želimo da ispisujemo u konzolu value
našeg inputa - čeka nas iznenađenje: u konzolu
će se ispisivati undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // ispisaće se undefined
}, 1000);
});
Stvar je u tome što imamo funkciju
u funkciji: postoji spoljna anonimna funkcija,
koja se poziva klikom i unutrašnja
anonimna funkcija, koju pokreće tajmer.
U spoljnoj funkciji this ukazuje
na input, ali u unutrašnjoj - ne. Postoji
gubitak konteksta.
Zašto se ispisuje undefined, a ne izbacuje se
greška u konzolu, kao što je bilo u prethodnim
lekcijama? Zato što this unutar funkcije,
koja se poziva preko setInterval, ukazuje
na window.
To znači da pokušavamo da pročitamo svojstvo
value objekta window, ovako: window.value,
a takvo svojstvo u njemu ne postoji, i dobijamo
undefined (ne grešku).
Ispravimo problem uvodenjem self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Neka je dat ovakav 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 koda je želeo da pritiskom na dugme,
vrednost tog dugmeta svake sekunde raste
za 1. Međutim, pritiskom na dugme
se uopšte ništa ne dešava. Ispravite grešku
autora koda. Napišite tekst u kom ćete
dati objašnjenje autoru koda, zašto se pojavila
njegova greška.