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:

html<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ă:

javascriptlet 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:

javascriptelem.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:

javascriptelem.addEventListener('click', function() {
  let self = this;
  
  setInterval(function() {
    console.log(self.value);
  }, 1000);
});
Задание 1

Să presupunem că este dat următorul cod:

html<input type="button" id="elem" value="1">
javascriptlet 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.