Časovniki in izguba konteksta v JavaScript
Pri uporabi časovnikov v obdelovalnikih dogodkov se soočamo s težavami izgube konteksta. Poglejmo si primer.
Recimo, da imamo vnosno polje:
<input id="elem" value="text">
Recimo, da ob kliku na to vnosno polje se sproži anonimna funkcija in znotraj te funkcije se zažene časovnik, ki vsako sekundo izpiše nekaj v konzolo:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // nekaj izpišemo v konzolo
}, 1000);
});
Zaenkrat vse deluje pravilno. Ampak recimo, da zdaj
želimo izpisati v konzolo value
našega vnosnega polja - čaka nas presenečenje: v konzolo
se bo izpisal undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // bo izpisal undefined
}, 1000);
});
Bistvo je v tem, da imamo funkcijo
znotraj funkcije: obstaja zunanja anonimna funkcija,
ki se pokliče ob kliku, in notranja
anonimna funkcija, ki jo zažene časovnik.
V zunanji funkciji this kaže
na vnosno polje, v notranji pa ne. Prišlo je do
izgube konteksta.
Zakaj se izpiše undefined in ne pride
do napake v konzoli, kot je bilo v prejšnjih
lekcijah? Ker this znotraj funkcije,
ki se kliče prek setInterval, kaže
na window.
To pomeni, da poskušamo prebrati lastnost
value objekta window, takole: window.value,
ampak takšne lastnosti v njem ni, in dobimo
undefined (ne napako).
Odpravimo težavo z uvedbo self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Recimo, da imamo takšno kodo:
<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);
});
Avtor kode je želel, da se ob pritisku na gumb
vrednost tega gumba vsako sekundo poveča
za 1. Vendar ob pritisku na gumb
sploh nič ne se zgodi. Popravite napako
avtorja kode. Napišite besedilo, v katerem
avtorju kode razložite, zakaj je prišlo do
napake.