Timers och kontextförlust i JavaScript
När man använder timers i händelsehanterare väntar problem med kontextförlust på oss. Låt oss titta på ett exempel.
Låt oss säga att vi har en input:
<input id="elem" value="text">
Låt oss säga att vid ett klick på denna input triggas en anonym funktion och inuti denna funktion startas en timer som varje sekund skriver ut något i konsolen:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // skriver ut något i konsolen
}, 1000);
});
Än så länge fungerar allt korrekt. Men låt oss nu säga
att vi vill skriva ut value
från vår input i konsolen - vi väntar en överraskning: i konsolen
kommer undefined att skrivas ut:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // kommer att skriva ut undefined
}, 1000);
});
Hela saken är att vi får en funktion
i en funktion: det finns en extern anonym funktion,
som anropas vid klick, och en intern
anonym funktion, som triggas av timern.
I den externa funktionen pekar this
på input, men i den interna - inte. Det finns en
kontextförlust.
Varför skrivs undefined ut, och inte
ett fel i konsolen, som det var i tidigare
lektioner? Eftersom this inuti funktionen
som anropas via setInterval, pekar
på window.
Det betyder att vi försöker läsa egenskapen
value från objektet window, så här: window.value,
och det finns ingen sådan egenskap i det, och vi får
undefined (inget fel).
Låt oss åtgärda problemet genom att introducera self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Låt oss säga att vi har denna kod:
<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);
});
Kodens författare ville att när knappen klickades,
ska värdet på denna knapp ökas med 1 varje sekund.
Men när man klickar på knappen
händer ingenting alls. Råtta författarens fel.
Skriv en text där du
ger en förklaring till kodens författare om varför felet
uppstod.