Timer și pierderea contextului în JavaScript
La utilizarea timerelor în manipulatoarele de evenimente ne așteaptă probleme cu pierderea contextului. Să ne uităm la un exemplu.
Să presupunem că avem un câmp de introducere:
<input id="elem" value="text">
Să presupunem că la click pe acest câmp de introducere se va executa o funcție anonimă și în interiorul acestei funcții va porni un timer, care la fiecare secundă va afișa ceva în consolă:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // afișăm ceva în consolă
}, 1000);
});
Deocamdată totul funcționează corect. Dar să presupunem acum
că vrem să afișăm în consolă value
câmpului nostru de introducere - ne așteaptă o surpriză: în consolă
va fi afișat undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // va afișa undefined
}, 1000);
});
Totul se datorează faptului că avem o funcție
într-o funcție: există o funcție anonimă externă,
care este apelată la click și o funcție anonimă
internă, pe care o pornește timerul.
În funcția externă this indică
către câmpul de introducere, dar în cea internă - nu. Are loc
pierderea contextului.
De ce se afișează undefined, și nu apare
o eroare în consolă, așa cum s-a întâmplat în lecțiile
anterioare? Pentru că this în interiorul funcției,
apelate prin setInterval, indică
către window.
Aceasta înseamnă că încercăm să citim proprietatea
value a obiectului window, astfel: window.value,
iar o astfel de proprietate nu există în el și obținem
undefined (nu o eroare).
Să corectăm problema introducând self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Să presupunem că este dat următorul cod:
<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);
});
Autorul codului dorea ca la apăsarea butonului,
valoarea acestui buton să crească cu 1 la fiecare secundă.
Cu toate acestea, la apăsarea butonului
nu se întâmplă nimic. Corectați eroarea
autorului codului. Scrieți un text în care
veți da o explicație autorului codului, de ce a apărut
eroarea lui.