Taimeri un konteksta zudums JavaScript
Lietojot taimerus notikumu apstrādātājos, mūs sagaida problēmas ar konteksta zudumu. Apskatīsim to ar piemēru.
Pieņemsim, ka mums ir ievades lauks:
<input id="elem" value="text">
Pieņemsim, ka noklikšķinot uz šī ievades lauka, tiks izsaukta anonīma funkcija un šīs funkcijas iekšienē startēsies taimeris, kas katru sekundi izvada kaut ko konsole:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // kaut ko izvadam konsolē
}, 1000);
});
Pagaidām viss darbojas pareizi. Bet pieņemsim, ka tagad
mēs vēlamies izvadīt konsolē value
mūsu ievades lauka - mūs sagaida pārsteigums: konsolē
tiks izvadīts undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // tiks izvadīts undefined
}, 1000);
});
Visa lieta ir tajā, ka mēs iegūstam funkciju
funkcijā: ir ārējā anonīmā funkcija,
kas tiek izsaukta, noklikšķinot, un iekšējā
anonīmā funkcija, ko palaiž taimeris.
Ārējā funkcijā this norāda
uz ievades lauku, bet iekšējā - nē. Notiek
konteksta zudums.
Kāpēc tiek izvadīts undefined, nevis tiek izmests
kļūdas paziņojums konsolē, kā tas bija iepriekšējās
nodarbībās? Tāpēc, ka this funkcijas iekšienē,
ko izsauc caur setInterval, norāda
uz window.
Tas nozīmē, ka mēs mēģinām nolasīt īpašību
value no objekta window, šādi: window.value,
bet šādas īpašības tajā nav, un mēs iegūstam
undefined (nevis kļūdu).
Izlabosim problēmu, ieviešot self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Pieņemsim, ka dots šāds kods:
<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);
});
Koda autors gribēja, lai, nospiežot pogu,
šīs pogas vērtība katru sekundi palielinātos
par 1. Tomēr, nospiežot pogu,
nekas vispār nenotiek. Izlabojiet koda autora
kļūdu. Uzrakstiet tekstu, kurā jūs
sniedzat skaidrojumu koda autoram, kāpēc radās
viņa kļūda.