Взгляни на один и тот же вызов функции с двух разных сторон:
function whoAmI() { return this; }
const obj = { whoAmI };
obj.whoAmI(); // → obj
new whoAmI(); // → новый объект { }
whoAmI.call({ x: 1 }); // → { x: 1 }
whoAmI(); // → window (или undefined)
Одна функция, четыре разных значения this — и это без всяких стрелочных функций. Причина в фундаментальной идее языка: this в JavaScript определяется не тем, где функция описана, а тем, как её вызывают. В большинстве других языков (Java, C++, Python) контекст функции статичен — ты видишь класс, ты знаешь this. Здесь — нет: смотреть надо не на функцию, а на строку её вызова.
Мануал разбирает все шесть сценариев вызова по одному, показывает типичные ошибки из реального кода и объясняет, как думать про this, чтобы вопрос «что тут будет?» отпадал сам собой.
Как читать мануал
Мануал разбит на 8 глав. Читать можно последовательно, но можно и по нужному разделу — главы независимы, ссылки на смежные темы стоят в тексте.
Глава 1. Тайна вокруг this. Почему this вообще странный. Ключевая идея: контекст определяется вызовом, не определением. Небольшой pre-tour по всему остальному мануалу.
Глава 2. Вызов функции. Самый частый сценарий (someFunc()): this — глобальный объект (window в браузере, global в Node) или undefined в строгом режиме. Плюс главная ловушка — this во вложенной функции.
Глава 3. Вызов метода. obj.method(): this — сам объект. Опасность: если метод отделить от объекта и вызвать отдельно, контекст теряется.
Глава 4. Вызов конструктора. new Fn(): this — новый пустой объект. Опасность: забыли написать new и не заметили.
Глава 5. Непрямой вызов. fn.call(context), fn.apply(context, args): this — переданный первым аргументом объект. Способ явно задать контекст.
Глава 6. Связанная функция. fn.bind(context): возвращает новую функцию с навсегда привязанным this. Плюс жёсткая привязка — когда контекст нельзя переопределить даже через .call().
Глава 7. Стрелочная функция. У стрелочной функции нет своего this — она наследует его из внешней области видимости. Часто это спасает от ошибок; иногда — создаёт новые. Опасность: определение метода объекта через стрелку.
Глава 8. Заключение. Ключевая mental model, cheatsheet-таблица правил и что делать дальше.
Краткий cheatsheet
Если нужна быстрая справка по всем правилам одной страницей, вот компактная сводка. Каждый пункт разбирается в отдельной главе с примерами:
- Простой вызов fn() → this = глобальный объект / undefined в строгом режиме
- Вызов метода obj.fn() → this = obj
- Явная привязка fn.call(x), fn.apply(x) → this = x
- Связанная функция fn.bind(x)() → this = x
- Конструктор new Fn() → this = новый объект
- Стрелочная функция → this = из окружающей области видимости (нет собственного)
Фраза «значение this зависит от контекста» часто путает: контекст здесь — не «место, где функция описана», а то, как её сейчас позвали. Именно эта разница между определением и вызовом — корень всех проблем. Со всеми деталями каждого сценария и типовыми ошибками из реального кода — в главах ниже.