Передача правильного контекста в setTimeout: пример на JS
Быстрый ответ
Чтобы сохранить контекст this, можно воспользоваться стрелочной функцией в роли колбэка для setTimeout:
setTimeout(() => this.myMethod(), 1000);
В качестве альтернативы можно привязать контекст с помощью bind к обычной функции:
setTimeout(this.myMethod.bind(this), 1000);

"Трудности" идентификации "this"
В JavaScript ключевое слово this зачастую ставит разработчиков в затруднительное положение. Особенно они встречаются при использовании setTimeout: this внезапно превращается в глобальный объект, вместо того чтобы ссылаться на прежний контекст.
Захват контекста с помощью замыкания
Один из способов решить данную проблему – сохранить текущее значение this, воспользовавшись замыканием, и в дальнейшем использовать его в теле функции, которую передаем в setTimeout:
var that = this;
setTimeout(function() {
that.myMethod();
}, 1000);
Использование Bind для сохранения контекста
Если вы думаете о совместимости со старыми версиями браузеров, например, Internet Explorer, Function.prototype.bind придет к вам на помощь. Он позволяет явно привязать контекст к функции, несмотря на попытки setTimeout его поменять:
setTimeout(this.myMethod.bind(this), 1000);
Дополнительные параметры в setTimeout и контекст
С появлением HTML5 спецификация setTimeout дополнилась возможностью передачи параметра this вместе с указанием временного интервала:
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:
setTimeout(function() {
this.navigate();
}.bind(ship), 1000);
2. Используем стрелочную функцию как компас:
setTimeout(() => {
ship.navigate();
}, 1000);
3. Сохраняем текущий контекст this:
var currentContext = this;
setTimeout(function() {
currentContext.navigate();
}, 1000);
В зависимости от ситуации выбирайте подходящий инструмент для сохранения контекста вашей функции (this).
Продвинутые "подводные камни"
Неявная и явная привязка
Иногда мы ошибочно полагаем, что переопределение контекста this с помощью bind, .call() или .apply() возвращает его в первоначальное состояние. Однако, переопределение не ведет к возвращению к исходному контексту.
Особенности стрелочных функций
Стрелочные функции не поддерживают привязку с помощью bind, call или apply, так как они уже фиксируют свой контекст при объявлении.
Совместимость с транспиляторами и полифилами
Помните, что при использовании нового синтаксиса setTimeout транспиляторы и полифилы могут не поддерживать его.


