ВНИМАНИЕ: Запись на курсы по HTML, CSS, JavaScript, PHP, Python, React, Vue, Laravel и другим фреймворкам и CMS,
а также: помощь в поиске работы и заказов, стажировка на реальных проектах→
⊗jsPmTrTCL 451 of 505 menu
Новый формат обучения! Репетиторство по программированию. Есть еще 3 свободных места! Жми для подробностей.

Таймеры и потеря контекста в 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. Однако, по нажатию на кнопку вообще ничего не происходит. Исправьте ошибку автора кода. Напишите текст, в котором вы дадите объяснение автору кода, почему возникла его ошибка.

byenru