Taimeriai ir konteksto praradimas JavaScript
Naudojant timer'ius įvykių dorokliuose mūsų laukia konteksto praradimo problemos. Pažvelkime į pavyzdį.
Tarkime, kad turime įvesties lauką:
<input id="elem" value="text">
Tegul paspaudus ant šio įvesties lauko suveikia anoniminė funkcija ir jos viduje paleidžiamas taimeris, kas sekundę išvedantis ką nors į konsolę:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // ką nors išvedame į konsolę
}, 1000);
});
Kol kas viskas veikia teisingai. Bet dabar tarkime,
kad norime išvesti į konsolę value
mūsų įvesties lauko - mūsų laukia siurprizas: į konsolę
bus išvedamas undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // bus išvedamas undefined
}, 1000);
});
Visa tai dėl to, kad mes gauname funkciją
funkcijoje: yra išorinė anoniminė funkcija,
kuri iškviečiama paspaudus, ir vidinė
anoniminė funkcija, kurią paleidžia taimeris.
Išorinėje funkcijoje this nurodo
į įvesties lauką, bet vidinėje - ne. Tai yra
konteksto praradimas.
Kodėl išvedamas undefined, o ne atsiranda
klaida konsolėje, kaip buvo ankstesnėse
pamokose? Todėl, kad this funkcijos viduje,
iškviečiamos per setInterval, nurodo
į window.
Tai reiškia, kad mes bandome perskaityti savybę
value iš objekto window, štai taip: window.value,
o tokios savybės jame nėra, ir mes gauname
undefined (ne klaidą).
Išspręskime problemą įvedant self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Tarkime, duotas toks kodas:
<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);
});
Kodo autorius norėjo, kad paspaudus mygtuką,
šio mygtuko reikšmė kiekvieną sekundę didėtų
1. Tačiau, paspaudus mygtuką
visiškai nieko neįvyksta. Ištaisykite kodo
autoriaus klaidą. Parašykite tekstą, kuriame
paaiškinsite kodėl atsirado jo klaida.