Какие методы для работы с контекстом this существуют и в чем их различия (bind, call, apply)
Что проверяют
Понимаете ли вы, что this определяется способом вызова функции, а не местом её объявления, и умеете ли управлять им явно. Следом почти всегда спрашивают, что будет с bind у стрелочной функции, или просят написать полифил bind.
Как отвечать
Сначала правило: this задаётся в момент вызова. obj.method() даёт this === obj, простой вызов fn() в строгом режиме даёт undefined, вызов через new даёт новый объект. Три метода задают this явно:
call(thisArg, a, b): вызывает функцию сразу, аргументы перечисляются через запятую;apply(thisArg, [a, b]): тоже вызывает сразу, но аргументы берёт массивом или массивоподобным объектом. Со spreadfn.call(ctx, ...args)решает ту же задачу, поэтомуapplyвстречается реже;bind(thisArg, a): ничего не вызывает, а возвращает новую функцию с привязаннымthisи, по желанию, частью аргументов. Это частичное применение:const add5 = add.bind(null, 5).
Детали, которые отличают сильный ответ:
- повторный
bind: контекст не меняет,fn.bind(a).bind(b)всё равно работает сa; newсильнееbind: при вызове привязанной функции черезnewпривязанныйthisигнорируется, а заранее переданные аргументы сохраняются;- стрелочные функции: своего
thisу них нет, он берётся из внешней области, иcall,apply,bindего не меняют, передаются только аргументы; - нестрогий режим:
nullиundefinedвthisArgзаменяются наglobalThis, примитивы оборачиваются в объекты. Модули и классы всегда в строгом режиме, там значение приходит как есть.
Типичный случай для bind: передать метод колбэком, например setTimeout(this.tick.bind(this), 1000), иначе контекст потеряется.
Где спотыкаются
Говорят, что this указывает на объект, которому принадлежит функция. Метод, переданный колбэком, теряет контекст, хотя по-прежнему «принадлежит» тому же объекту.
Путают, какой метод вызывает функцию сразу. bind только возвращает новую, и fn.bind(ctx) без скобок вызова ничего не выполнит.
Пытаются привязать контекст стрелочной функции через bind и удивляются, что ничего не меняется.