> Как вызвать функцию, чтобы this указывал на нужный объект, а не на window в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Домклик
Стек: JavaScript
> Пример ответа
Короткий ответ
Чтобы вызвать функцию с нужным значением this, используй call, apply или bind. call и apply вызывают функцию сразу, передавая контекст первым аргументом, а bind возвращает новую функцию с привязанным this. Также можно использовать стрелочные функции - они не имеют собственного this и берут его из внешнего лексического окружения. В строгом режиме ('use strict') this в обычном вызове будет undefined, а не window.
Подробное объяснение
this в JavaScript определяется тем, как вызывается функция, а не где она объявлена. При обычном вызове fn() в нестрогом режиме this указывает на глобальный объект (window в браузере). Чтобы явно задать контекст, есть три метода:
fn.call(context, arg1, arg2, ...)- вызывает функцию сразу, передавая аргументы по отдельности.fn.apply(context, [argsArray])- то же самое, но аргументы передаются массивом или array-like объектом.fn.bind(context, ...args)- возвращает новую функцию с навсегда привязаннымthis(и, опционально, частью аргументов). Вызов происходит позже.
Важно: bind не изменяет исходную функцию, а создаёт обёртку. Привязку нельзя переопределить через call или apply у уже связанной функции.
Стрелочные функции (=>) полностью игнорируют call, apply и bind - их this фиксируется на момент создания и берётся из внешней функции или модуля.
На практике
В реальном коде чаще всего bind используют для передачи метода объекта в качестве callback (например, в обработчиках событий или setTimeout). call и apply удобны для заимствования методов - например, Array.prototype.slice.call(arguments).
Также apply полезен, когда количество аргументов заранее неизвестно или они уже лежат в массиве. В современном JavaScript для этого чаще используют spread-оператор: fn(...args) - но он не меняет this.
Пример кода
JAVASCRIPTconst user = {name: 'Анна',greet(greeting, punctuation) {console.log(`${greeting}, ${this.name}${punctuation}`);}};const otherUser = { name: 'Пётр' };// call - сразу, аргументы по отдельностиuser.greet.call(otherUser, 'Привет', '!'); // "Привет, Пётр!"// apply - сразу, аргументы массивомuser.greet.apply(otherUser, ['Здравствуйте', '...']); // "Здравствуйте, Пётр..."// bind - новая функция с привязанным thisconst boundGreet = user.greet.bind(otherUser, 'Хай');boundGreet('?'); // "Хай, Пётр?"// стрелочная функция - this из внешнего контекстаconst arrowGreet = () => console.log(this); // this = window (или undefined в strict)
Как отвечать на собеседовании
Начни с прямого ответа: call, apply, bind. Затем кратко объясни разницу: call и apply - немедленный вызов, bind - создание новой функции. Упомяни стрелочные функции как альтернативу. Приведи пример из практики - например, почему setTimeout(this.method, 100) теряет контекст и как это исправить через bind. Если спросят про строгий режим - скажи, что в 'use strict' this при обычном вызове будет undefined, что защищает от случайной записи в глобальный объект.
Что проверяет интервьюер
Интервьюер оценивает:
- понимание динамической природы
this(важен способ вызова, а не объявление); - знание трёх методов управления контекстом и их отличий;
- умение объяснить, почему
bindне работает со стрелочными функциями; - способность применить знания к реальной задаче - например, потеря контекста в callback.
Типичные ошибки
- Путать
callиapply- забывать, чтоapplyпринимает массив аргументов. - Думать, что
bindвызывает функцию сразу - на самом деле он возвращает новую функцию. - Пытаться переопределить
thisу стрелочной функции черезcall/apply- это не сработает. - Забывать, что
bindсоздаёт новую функцию, поэтому её нельзя использовать для удаления обработчика, если не сохранить ссылку. - В нестрогом режиме полагаться на
windowкак на "дефолтный"this- лучше всегда явно передавать контекст.
> Похожие задачи по frontend
Как предотвратить двойной заказ при двойном клике на кнопку?
Почему this равен window, а this.name выводит другое значение в JavaScript
На какой стадии отрабатывают внешние нецелевые обработчики событий в DOM
Почему parseInt в JavaScript может возвращать NaN и как влияет второй аргумент
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью