Таймеры і страта кантэксту ў JavaScript
Пры выкарыстанні таймераў у апрацоўшчыках падзей нас падпяшаюць праблемы са стратай кантэксту. Давайце паглядзім на прыкладзе.
Хай у нас ёсць інпут:
<input id="elem" value="text">
Хай па кліку на гэты інпут спрацуе ананімная функцыя і ўнутры гэтай функцыі запусціцца таймер, кожную секунду які выводзіць што-небудзь у кансоль:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // што-небудзь выводзім у кансоль
}, 1000);
});
Пакуль усё працуе правільна. Але хай цяпер
мы хочам выводзіць у кансоль value
нашага інпута - нас чакае сюрпрыз: у кансоль
будзе выводзіцца undefined
:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // будзе выводзіцца undefined
}, 1000);
});
Уся справа ў тым, што ў нас атрымліваецца функцыя
ў функцыі: ёсць знешняя ананімная функцыя,
якая выклікаецца па кліку і ўнутраная
ананімная функцыя, якую запускае таймер.
У знешняй функцыі this
паказвае
на інпут, але ва ўнутранай - не. Мае месца
страта кантэксту.
Чаму выводзіцца 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
. Аднак, па націсканні на кнопку
наогул нічога не адбываецца. Выправіце памылку
аўтара кода. Напішыце тэкст, у якім вы
дасце тлумачэнне аўтару кода, чаму ўзнікла
яго памылка.