Ajastimet ja kontekstin menetys JavaScriptissä

Ajastimia käytettäessä tapahtumankäsittelijöissä kohtaamme ongelmia kontekstin menetyksen kanssa. Katsotaanpa esimerkkiä.

Oletetaan, että meillä on syötekenttä:

html<input id="elem" value="text">

Oletetaan, että klikatessa tätä syötekenttää suoritetaan nimetön funktio ja tämän funktion sisällä käynnistetään ajastin, joka tulostaa jotakin konsoliin sekunnin välein:

javascriptlet elem = document.querySelector('#elem');

elem.addEventListener('click', function() {
  setInterval(function() {
    console.log('!!!'); // tulostetaan jotakin konsoliin
  }, 1000);
});

Toistaiseksi kaikki toimii oikein. Mutta oletetaan nyt, että haluamme tulostaa konsoliin value syötekentästämme - meitä odottaa yllätys: konsoliin tulostuu undefined:

javascriptelem.addEventListener('click', function() {
  setInterval(function() {
    console.log(this.value); // tulostuu undefined
  }, 1000);
});

Kyse on siitä, että meillä on funktio funktion sisällä: on ulkoinen nimetön funktio, jota kutsutaan klikkauksen yhteydessä, ja sisäinen nimetön funktio, jonka ajastin käynnistää. Ulkoisessa funktiossa this viittaa syötekenttään, mutta sisäisessä - ei. Tässä on kyse kontekstin menetyksestä.

Miksi tulostuu undefined, eikä konsoliin tule virhettä, kuten aiemmissa oppitunneissa? Koska this funktion sisällä, jota kutsutaan setInterval:n kautta, viittaa window-objektiin.

Tämä tarkoittaa, että yritämme lukea value-ominaisuuden window-objektilta, näin: window.value, mutta sellaista ominaisuutta siinä ei ole, ja saamme undefined (ei virhettä).

Korjataan ongelma ottamalla käyttöön self:

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

Oletetaan, että on annettu tällainen koodi:

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);
});

Koodin kirjoittaja halusi, että painettaessa nappia, tämän napin arvo kasvaisi joka sekunti 1:llä. Kuitenkin napin painalluksella ei tapahdu mitään. Korjatkaa koodin kirjoittajan virhe. Kirjoittakaa teksti, jossa annatte selityksen koodin kirjoittajalle, miksi hänen virheensä syntyi.