call, apply и bind в JavaScript — как и когда использовать

Введение
Вы, вероятно, уже встречали встроенные методы для массивов и строк в JavaScript. Меньше говорят о методах call, apply и bind, хотя они очень полезны. Эти методы управляют тем, что внутри функции доступно через ключевое слово this. Понимание их отличий важно при отладке, оптимизации и подготовке к собеседованиям.
Определение: this — ссылка на «контекст» вызова функции; её значение зависит от способа вызова функции.
Общая идея и сигнатуры
- func.call(thisArg, arg1, arg2, …)
- func.apply(thisArg, [arg1, arg2, …])
- func.bind(thisArg, arg1?, arg2?, …)
Короткая память: call = отдельные аргументы, apply = массив, bind = новая функция.
Пример call
Оригинальный пример с комментариями сохранён и локализован.
let obj = {
name: "John",
surname: "Doe",
getFullName: function(){
console.log(this.name + " " + this.surname);
}
}
obj.getFullName(); // John DoeПрименим getFullName к другому объекту через call:
const obj2 = {
name: "Jane",
surname: "Doe"
}
obj.getFullName.call(obj2); // Jane Doecall также принимает дополнительные аргументы:
let obj = {
name: "John",
surname: "Doe",
getFullName: function(age, gender){
console.log(this.name + " " + this.surname + " " + age + " " + gender);
}
}
obj.getFullName.call(obj2, 21, "female"); // Jane Doe 21 femaleПример apply
apply ведёт себя почти так же, но аргументы передаются массивом:
const obj = {
name: "John",
surname: "Doe",
getFullName: function(age, gender){
console.log(this.name + " " + this.surname + " " + age + " " + gender);
}
}
obj.getFullName.apply(obj2, [21, "female"]); // Jane Doe 21 femaleКогда использовать apply: удобен, если аргументы уже в виде массива или вы хотите напрямую передать массив (например, результат map/arguments).
Пример bind
bind возвращает новую функцию с навсегда привязанным this. Это полезно, когда вызывают функцию позже или передают её как коллбэк.
const obj = {
name: "John",
surname: "Jane",
getFullName: function(){
console.log(this.name + " " + this.surname);
}
}
const obj2 = {
name: "Jane",
surname: "Doe"
}
let func = obj.getFullName.bind(obj2);
func(); // Jane Doebind можно использовать частично применять аргументы (partial application):
function add(a, b){ return a + b; }
const add5 = add.bind(null, 5);
console.log(add5(10)); // 15Когда использовать каждый метод
- call — единичный вызов с нужным this и обычным списком аргументов.
- apply — единичный вызов, когда аргументы в виде массива.
- bind — когда нужно сохранить контекст на будущее или передать функцию как коллбэк.
Важно: bind возвращает новую функцию, а не изменяет оригинал.
Когда это не сработает: подводные камни
Стрелочные функции игнорируют bind/call/apply для this. Они наследуют this из внешнего лексического окружения. Если метод объявлен как стрелочная функция, вызов через call/apply/bind не изменит this.
Привязка в строгом режиме может дать undefined вместо глобального объекта.
Если метод используется вместе с new, bind не всегда ведёт себя интуитивно: при вызове через new привязка this в bind игнорируется и создаётся новый объект.
Ментальные модели и эвристики
- Представьте, что call/apply «подменяют» this на время вызова. bind «приклеивает» this навсегда к возвращённой функции.
- call = «позвонить сейчас», apply = «позвонить с пакетом аргументов», bind = «приклеить трубку, чтобы позвонить позже».
Краткая памятка (cheat sheet)
- call(thisArg, arg1, arg2)
- apply(thisArg, [arg1, arg2])
- bind(thisArg, arg1?) -> returns function
Примеры ошибок и тесты
Критерии приёмки:
- Функция должна правильно выводить имя для разных объектов при использовании call. Тест: вызвать getFullName.call(obj2) и сверить вывод.
- apply должен принимать массив: вызвать getFullName.apply(obj2, argsArray).
- bind должен возвращать вызываемую функцию, которая при вызове использует связанный контекст.
- Стрелочная функция не должна менять this при вызове через call/apply/bind. Тест: создать стрелочную функцию и попытаться изменить её this — значение не изменится.
Тестовые случаи (пример):
- Обычная функция, call изменяет this — PASS.
- Обычная функция, apply с массивом аргументов — PASS.
- bind возвращает функцию, выполняемую позже — PASS.
- Стрелочная функция, попытка bind — this не изменился — PASS.
Альтернативы и сопутствующие подходы
- В современных приложениях часто используют замыкания или контекст через класс/компонентные шаблоны (например, в React) вместо явной привязки this.
- Вместо bind для частичного применения можно использовать стрелочные функции или функции высшего порядка.
Роль разработчика — чеклист при работе с контекстом
- Бэкэнд/Node: избегайте неявного глобального this; используйте bind или стрелочные функции для коллбэков.
- Фронтенд/DOM: при передаче метода как обработчика событий используйте bind или обёртку, чтобы сохранить контекст компонента.
- Тестирование: проверяйте поведение this в unit-тестах при помощи call/apply.
Часто задаваемые вопросы
Чем call отличается от apply?
call принимает список аргументов, apply — массив аргументов.
Когда лучше использовать bind?
Когда нужно сохранить контекст для позднего вызова (коллбэки, обработчики событий, таймеры).
Меняет ли bind this в стрелочной функции?
Нет. Стрелочная функция не имеет собственного this и игнорирует call/apply/bind.
1‑строчный глоссарий
this — ссылка на объект контекста вызова функции; значение зависит от способа вызова.
Резюме
- call, apply и bind управляют значением this.
- call и apply вызывают функцию сразу; bind возвращает новую функцию.
- Стрелочные функции не реагируют на привязку контекста.
Важно: при использовании этих методов следите за тем, какая функция объявлена (обычная или стрелочная) и где вы планируете её вызывать.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone