Взгляни на один и тот же вызов функции с двух разных сторон:

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

Если нужна быстрая справка по всем правилам одной страницей, вот компактная сводка. Каждый пункт разбирается в отдельной главе с примерами:

  1. Простой вызов fn()this = глобальный объект / undefined в строгом режиме
  2. Вызов метода obj.fn()this = obj
  3. Явная привязка fn.call(x), fn.apply(x)this = x
  4. Связанная функция fn.bind(x)()this = x
  5. Конструктор new Fn()this = новый объект
  6. Стрелочная функцияthis = из окружающей области видимости (нет собственного)

Фраза «значение this зависит от контекста» часто путает: контекст здесь — не «место, где функция описана», а то, как её сейчас позвали. Именно эта разница между определением и вызовом — корень всех проблем. Со всеми деталями каждого сценария и типовыми ошибками из реального кода — в главах ниже.