Как вызвать функцию, чтобы this указывал на нужный объект, а не на window в JavaScript
Что проверяют
Понимаете ли вы, что this определяется способом вызова, а не местом объявления функции. Следом почти всегда дают код: метод передали в setTimeout или в обработчик события, что выведется и как это починить.
Как отвечать
Сначала правило: у обычной функции this задаётся в момент вызова, по приоритету:
- вызов через
new:thisэто только что созданный объект; - явная привязка:
fn.call(obj, a, b)иfn.apply(obj, [a, b])вызывают функцию сразу, разница только в передаче аргументов.fn.bind(obj)ничего не вызывает, а возвращает новую функцию с навсегда привязанным контекстом; - вызов как метода: в
obj.method()значениеthisэтоobj, объект слева от точки; - простой вызов
fn(): в нестрогом режиме это глобальный объект (windowв браузере), в строгомundefined. Модули ES и тела классов всегда строгие, поэтому в современном коде вы чаще увидитеTypeError, чемwindow.
Стрелочные функции стоят особняком: своего this у них нет, они берут его из окружающей области при создании, и call, apply, bind его не меняют.
Практические способы не потерять контекст:
- обёртка-стрелка:
setTimeout(() => this.save(), 100); - привязка в классе:
bindв конструкторе или поле класса со стрелкойhandleClick = () => {...}; - обработчики DOM: в
addEventListenerобычная функция получаетthis, равныйevent.currentTarget, а стрелка нет.
Где спотыкаются
Делают метод объекта стрелочной функцией и ждут, что this будет объектом. Стрелка возьмёт this снаружи литерала, то есть из модуля или глобальной области.
Думают, что bind можно вызвать повторно и перепривязать контекст. Второй bind на уже привязанной функции контекст не меняет, только добавляет аргументы.
Не видят потерю контекста при деструктуризации: const { save } = obj; save() это уже простой вызов, и this внутри не obj.