Таймери и загуба на контекст в JavaScript
При използване на таймери в манипулатори на събития ни очакват проблеми със загуба на контекст. Нека разгледаме пример.
Да предположим, че имаме input поле:
<input id="elem" value="text">
Да предположим, че при клик върху това input поле се изпълнява анонимна функция и вътре в тази функция се стартира таймер, който всяка секунда извежда нещо в конзолата:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // извеждаме нещо в конзолата
}, 1000);
});
Дотук всичко работи правилно. Но сега да предположим, че
искаме да извеждаме в конзолата value
на нашия input - ни очаква изненада: в конзолата
ще се извежда undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // ще се извежда undefined
}, 1000);
});
Цялата работа е в това, че се получава функция
във функция: има външна анонимна функция,
която се извиква при клик и вътрешна
анонимна функция, която се стартира от таймера.
Във външната функция this сочи
към input полето, но във вътрешната - не. Имаме
загуба на контекст.
Защо се извежда undefined, а не се появява
грешка в конзолата, както беше в предишните
уроци? Защото this във функцията,
извикана чрез setInterval, сочи
към window.
Това означава, че се опитваме да прочетем свойството
value на обекта window, ето така: window.value,
а такова свойство в него няма, и получаваме
undefined (не грешка).
Нека поправим проблема чрез въвеждане на self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Даден е следният код:
<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);
});
Авторът на кода е искал при натискане на бутона,
стойността на този бутон да се увеличава всяка секунда
с 1. Обаче, при натискане на бутона
изобщо нищо не се случва. Поправете грешката
в кода на автора. Напишете текст, в който
дадете обяснение на автора на кода, защо е възникнала
неговата грешка.