Ajastid ja konteksti kaotus JavaScriptis
Ajastite kasutamisel sündmuste töötlejates ootavad meid probleemid konteksti kaotusega. Vaatame seda näite varal.
Oletame, et meil on sisendväli:
<input id="elem" value="text">
Oletame, et klõpsates sellel sisendväljal käivitub anonüümne funktsioon ja selle funktsiooni sees käivitub ajasti, mis iga sekund väljastab midagi konsooli:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // väljastame midagi konsooli
}, 1000);
});
Siiani kõik töötab õigesti. Kuid nüüd oletame, et
me tahame konsooli väljastada value
meie sisendväljalt - meid ootab üllatus: konsooli
väljub undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // väljub undefined
}, 1000);
});
Asi on selles, et meil tekib funktsioon
funktsiooni sees: on väline anonüümne funktsioon,
mida kutsutakse välja klõpsu peale ja sisemine
anonüümne funktsioon, mida käivitab ajasti.
Välises funktsioonis viitab this
sisendväljale, kuid sisemises - mitte. Tekib
konteksti kaotus.
Miks väljub undefined, mitte ei teki
veateadet konsooli, nagu see oli eelmistes
õppetükides? Sellepärast, et this funktsiooni sees,
mida kutsutakse välja läbi setInterval, viitab
window-ile.
See tähendab, et me püüame lugeda omadust
value objektilt window, niimoodi: window.value,
kuid sellist omadust seal pole, ja me saame
undefined (mitte vea).
Parandame probleemi self kasutuselevõtuga:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Oletame, et on antud selline kood:
<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);
});
Koodi autor soovis, et nuppu vajutades
suureneks selle nupu väärtus iga sekund
1 võrra. Kuid nuppu vajutades
ei juhtu aga midagi. Parandage koodi autori
viga. Kirjutage tekst, milles annate
selgituse koodi autorile, miks tekkis
tema viga.