Различие методов 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 и, возможно, с частично переданными аргументами.