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ä:
<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:
let 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:
elem.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:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Oletetaan, että on annettu tällainen koodi:
<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);
});
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.