Передача правильного контекста в setTimeout: пример на JS

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы сохранить контекст this, можно воспользоваться стрелочной функцией в роли колбэка для setTimeout:

JS
Скопировать код
setTimeout(() => this.myMethod(), 1000);

В качестве альтернативы можно привязать контекст с помощью bind к обычной функции:

JS
Скопировать код
setTimeout(this.myMethod.bind(this), 1000);
Кинга Идем в IT: пошаговый план для смены профессии

"Трудности" идентификации "this"

В JavaScript ключевое слово this зачастую ставит разработчиков в затруднительное положение. Особенно они встречаются при использовании setTimeout: this внезапно превращается в глобальный объект, вместо того чтобы ссылаться на прежний контекст.

Захват контекста с помощью замыкания

Один из способов решить данную проблему – сохранить текущее значение this, воспользовавшись замыканием, и в дальнейшем использовать его в теле функции, которую передаем в setTimeout:

JS
Скопировать код
var that = this;
setTimeout(function() {
  that.myMethod();
}, 1000);

Использование Bind для сохранения контекста

Если вы думаете о совместимости со старыми версиями браузеров, например, Internet Explorer, Function.prototype.bind придет к вам на помощь. Он позволяет явно привязать контекст к функции, несмотря на попытки setTimeout его поменять:

JS
Скопировать код
setTimeout(this.myMethod.bind(this), 1000);

Дополнительные параметры в setTimeout и контекст

С появлением HTML5 спецификация setTimeout дополнилась возможностью передачи параметра this вместе с указанием временного интервала:

JS
Скопировать код
setTimeout(function(a) {
  this.myMethod();
}, 1000, this);

Однако, стоит помнить, что не все старые версии браузеров поддерживают данную возможность, так что проверьте совместимость.

Помощники из библиотек

Библиотеки вроде jQuery и lodash предлагают свои методы для сохранения контекста this при использовании setTimeout. Примерами служат методы $.proxy() для jQuery и _.bind() для lodash.

Обход ограничений в старых версиях IE

К сожалению, старые версии Internet Explorer нередко испытывают трудности с методом bind. В таких случаях, использование замыкания или методов из библиотек, таких как jQuery, может стать единственной возможностью.

Вопросы производительности

Между упомянутыми методами есть незначительные различия в производительности. Они не влияют на setTimeout, но замыкания могут потреблять больше памяти, чем bind или стрелочные функции, в связи с созданием дополнительной области видимости.

Визуализация

Представьте, что наша функция – это корабль, который должен оставаться в своем контексте this. Для этого мы можем использовать следующие инструменты:

1. Привязываем через Bind:

JS
Скопировать код
setTimeout(function() {
  this.navigate();
}.bind(ship), 1000);

2. Используем стрелочную функцию как компас:

JS
Скопировать код
setTimeout(() => {
  ship.navigate();
}, 1000);

3. Сохраняем текущий контекст this:

JS
Скопировать код
var currentContext = this;
setTimeout(function() {
  currentContext.navigate();
}, 1000);

В зависимости от ситуации выбирайте подходящий инструмент для сохранения контекста вашей функции (this).

Продвинутые "подводные камни"

Неявная и явная привязка

Иногда мы ошибочно полагаем, что переопределение контекста this с помощью bind, .call() или .apply() возвращает его в первоначальное состояние. Однако, переопределение не ведет к возвращению к исходному контексту.

Особенности стрелочных функций

Стрелочные функции не поддерживают привязку с помощью bind, call или apply, так как они уже фиксируют свой контекст при объявлении.

Совместимость с транспиляторами и полифилами

Помните, что при использовании нового синтаксиса setTimeout транспиляторы и полифилы могут не поддерживать его.

Полезные материалы

  1. this – JavaScript | MDN
  2. Привязка функции
  3. Function.prototype.bind() – JavaScript | MDN
  4. Глобальная функция setTimeout – Web APIs | MDN
  5. Передача правильного контекста "this" в колбэк setTimeout? – Stack Overflow
  6. Замыкания – JavaScript | MDN
  7. Выражения стрелочных функций – JavaScript | MDN
Свежие материалы