Различие методов call apply bind
Методы call, apply и bind в JavaScript используются для явного управления значением this при вызове функций. Все три метода принадлежат прототипу Function.prototype, что означает: они доступны для любой функции.
Хотя основная цель у них одна — установить контекст (this), — они отличаются по синтаксису вызова, времени выполнения, способу передачи аргументов и возвращаемому значению.
1. Контекст (this) и его значение
Во многих случаях значение this зависит от контекста вызова функции. Когда мы хотим вручную указать, чему должно быть равно this, используются call, apply или bind.
Пример:
function greet() {
console.log(\`Привет, ${this.name}\`);
}
const person = { name: "Анна" };
greet.call(person); // Привет, Анна
2. Метод call()
Сигнатура:
func.call(thisArg, arg1, arg2, ...)
Описание:
-
Вызывает функцию с указанным this.
-
Принимает аргументы через запятую.
-
Функция выполняется немедленно.
Пример:
function introduce(age, city) {
console.log(\`${this.name}, ${age} лет, из ${city}\`);
}
const user = { name: "Иван" };
introduce.call(user, 25, "Москва");
// Иван, 25 лет, из Москва
3. Метод apply()
Сигнатура:
func.apply(thisArg, \[arg1, arg2, ...\])
Описание:
-
Почти то же самое, что call.
-
Отличие — аргументы передаются в виде массива.
-
Выполняет функцию сразу.
Пример:
function introduce(age, city) {
console.log(\`${this.name}, ${age} лет, из ${city}\`);
}
const user = { name: "Мария" };
introduce.apply(user, \[30, "Казань"\]);
// Мария, 30 лет, из Казань
Когда удобно использовать apply:
Когда аргументы уже собраны в массив или псевдомассив:
const args = \[40, "Самара"\];
introduce.apply(user, args);
Также apply часто использовался для передачи массивов в методы, принимающие список аргументов (до появления spread-оператора):
const numbers = \[1, 2, 3, 4\];
const max = Math.max.apply(null, numbers); // 4
4. Метод bind()
Сигнатура:
const newFunc = func.bind(thisArg, arg1, arg2, ...)
Описание:
-
Не вызывает функцию сразу.
-
Возвращает новую функцию, где this уже привязан.
-
Можно передавать часть аргументов сразу (частичное применение).
Пример:
function greet(city) {
console.log(\`${this.name} из ${city}\`);
}
const user = { name: "Дмитрий" };
const boundGreet = greet.bind(user);
boundGreet("Томск"); // Дмитрий из Томск
5. Частичное применение аргументов с bind
Можно заранее передать некоторые аргументы, остальные — при вызове:
function sum(a, b, c) {
return a + b + c;
}
const addFive = sum.bind(null, 2, 3);
console.log(addFive(10)); // 15
6. Сравнение поведения: вызов vs привязка
Метод | Вызывает функцию сразу | Передача аргументов | Возвращает новую функцию |
---|---|---|---|
call | Да | Через запятую | Нет |
--- | --- | --- | --- |
apply | Да | Массив аргументов | Нет |
--- | --- | --- | --- |
bind | Нет | Через запятую | Да |
--- | --- | --- | --- |
7. Разница в контексте времени выполнения
call и apply:
Они меняют this и сразу выполняют функцию, что важно, если нужно единовременно вызвать её в определённом контексте.
bind:
Создаёт новую функцию, которую можно использовать позже, с уже зафиксированным this. Особенно полезно в обработчиках событий, таймерах, callback'ах.
Пример:
const user = {
name: "Алексей",
sayHi() {
console.log(\`Привет от ${this.name}\`);
}
};
setTimeout(user.sayHi, 1000); // undefined или ошибка (потеря контекста)
setTimeout(user.sayHi.bind(user), 1000); // Привет от Алексей
8. Сравнение передачи аргументов
function log(a, b, c) {
console.log(\`${this.prefix}: ${a}, ${b}, ${c}\`);
}
const ctx = { prefix: "Лог" };
// call: через запятую
log.call(ctx, 1, 2, 3);
// apply: массив
log.apply(ctx, \[4, 5, 6\]);
// bind: фиксирует контекст и аргументы
const boundLog = log.bind(ctx, 7, 8);
boundLog(9); // Лог: 7, 8, 9
9. bind() с методами классов и объектов
Когда методы объектов передаются как callback-функции, this теряется. Чтобы сохранить контекст, нужно использовать bind.
Пример:
class Counter {
constructor() {
this.count = 0;
}
increment() {
this.count++;
console.log(this.count);
}
}
const counter = new Counter();
setInterval(counter.increment, 1000); // NaN или ошибка, this — window
// Правильно:
setInterval(counter.increment.bind(counter), 1000); // 1, 2, 3...
10. Особенности bind с new
Когда функцию, привязанную через bind, вызывают как конструктор с new, поведение bind частично теряется — this будет указывать на новый объект, а не на привязанный контекст:
function User(name) {
this.name = name;
}
const boundUser = User.bind({}); // привязали пустой объект
const u = new boundUser("Лена");
console.log(u.name); // Лена
new переопределяет this, даже если функция была заранее привязана через bind.
11. Работа с псевдомассивами (arguments, NodeList)
call и apply часто используются для применения массивных методов к объектам, не являющимся настоящими массивами:
function example() {
const argsArray = Array.prototype.slice.call(arguments);
console.log(argsArray);
}
example(1, 2, 3); // \[1, 2, 3\]
С появлением Array.from() и спред-синтаксиса (...), такая техника стала реже использоваться, но она демонстрирует силу call.
12. Совместное использование
-
Используйте call, если аргументы известны и просты.
-
Используйте apply, если аргументы уже в массиве.
-
Используйте bind, если вы хотите создать новую функцию с фиксированным this и, возможно, с частично переданными аргументами.