Learn JavaScript

call() - метод для вызова функции с заданным this в JavaScript

call() - это метод функций, который сразу вызывает функцию с указанным this и списком аргументов.

Если говорить просто, call() нужен, когда функцию надо выполнить прямо сейчас, но с нужным контекстом.

Синтаксис

Базовая запись выглядит так:

fn.call(thisArg, arg1, arg2, arg3)

Где:

  • thisArg - значение, которое станет this внутри функции
  • arg1, arg2, arg3 - аргументы функции

Что делает call()

call() сразу вызывает функцию.

Это главное отличие от bind(), который только создаёт новую функцию.

function greet() {
  console.log("Привет");
}

greet.call(null); // "Привет"

Здесь функция выполняется сразу в момент вызова call().

Зачем передавать this через call()

Чаще всего call() используют, когда функция зависит от this.

function showName() {
  console.log(this.name);
}

const user = { name: "Анна" };

showName.call(user); // "Анна"

Без call() эта функция не знает, к какому объекту должна относиться.

Пример с обычной функцией и разными объектами

Одна и та же функция может работать с разными объектами.

function showName() {
  console.log(this.name);
}

const user1 = { name: "Анна" };
const user2 = { name: "Игорь" };

showName.call(user1); // "Анна"
showName.call(user2); // "Игорь"

Это удобно, когда логика одна и та же, а данные разные.

call() и аргументы

Через call() можно не только передать this, но и обычные аргументы функции.

function greet(prefix, suffix) {
  console.log(`${prefix}${this.name}${suffix}`);
}

const user = { name: "Анна" };

greet.call(user, "Привет, ", "!"); // "Привет, Анна!"

Порядок тут такой:

  • первым идёт thisArg
  • дальше идут обычные аргументы функции

call() полезен для “заимствования” метода

Иногда нужно использовать метод одного объекта для другого значения.

Например, старый и известный приём:

function logArguments() {
  const result = Array.prototype.join.call(arguments, ", ");
  console.log(result);
}

logArguments("a", "b", "c"); // "a, b, c"

Здесь join() из массива используется для псевдомассива arguments.

Это полезно, когда у значения нет нужного метода, но по структуре оно подходит.

call() и методы объекта

Иногда метод выносят из объекта в отдельную переменную, и тогда this теряется.

const user = {
  name: "Анна",
  showName() {
    console.log(this.name);
  },
};

const show = user.showName;

show.call(user); // "Анна"

call(user) позволяет явно вернуть нужный контекст.

Чем call() отличается от apply()

Оба метода вызывают функцию сразу и оба работают с this.

Разница в том, как передаются аргументы:

  • call() принимает аргументы по одному
  • apply() принимает аргументы массивом

call():

function sum(a, b) {
  return a + b;
}

console.log(sum.call(null, 2, 3)); // 5

apply():

function sum(a, b) {
  return a + b;
}

console.log(sum.apply(null, [2, 3])); // 5

С появлением spread apply() стали использовать реже, потому что массив теперь легко раскрыть через ....

Чем call() отличается от bind()

Это ещё одно важное различие:

  • call() вызывает функцию сразу
  • bind() возвращает новую функцию на будущее

Пример:

function greet() {
  console.log(this.name);
}

const user = { name: "Анна" };

greet.call(user); // "Анна"

const boundGreet = greet.bind(user);
boundGreet(); // "Анна"

Если выполнить нужно немедленно, подходит call().

Если функцию надо подготовить сейчас, а запустить позже, подходит bind().

call() и стрелочные функции

Со стрелочными функциями call() не даёт обычного эффекта привязки this.

const arrow = () => {
  console.log(this);
};

arrow.call({ name: "Анна" });

Синтаксически это работает, но this стрелочной функции не становится объектом из call(), потому что у стрелочных функций нет собственного this.

Поэтому call() обычно используют с обычными функциями.

Когда это полезно

call() особенно удобен, когда:

  • нужно сразу вызвать функцию с заданным this
  • одна функция должна поработать с разными объектами
  • нужно временно использовать метод одного типа данных для другого значения
  • надо явно управлять контекстом вызова

Пример:

function printPrice(currency) {
  console.log(`${this.price} ${currency}`);
}

const product = { price: 1500 };

printPrice.call(product, "руб.");

Частые ошибки

Путать call() и bind()

function greet() {
  console.log(this.name);
}

const user = { name: "Анна" };

const result = greet.call(user);

Здесь result - это не новая функция, а результат выполнения greet.

call() ничего не откладывает на потом.

Забывать, что первый аргумент call() - это this

function greet(message) {
  console.log(message, this.name);
}

const user = { name: "Анна" };

greet.call(user, "Привет");

Если перепутать порядок, контекст и аргументы окажутся не там, где ожидаются.

Ожидать, что call() “исправит” this у стрелочной функции

Для стрелочных функций call() обычно не используют для привязки this.

Использовать call() там, где this вообще не нужен

function sum(a, b) {
  return a + b;
}

sum.call(null, 2, 3);

Так можно, но если функция не использует this, обычный вызов часто проще:

sum(2, 3);

Пытаться вызвать call() не на функции

const user = {};

// user.call(null); // TypeError

call() - это метод именно функций.

Быстрая памятка

  • call() - это метод функций
  • call() вызывает функцию сразу
  • первый аргумент call() - это this
  • остальные аргументы передаются в функцию по одному
  • call() отличается от apply() способом передачи аргументов
  • call() отличается от bind() тем, что не возвращает новую функцию
  • со стрелочными функциями call() обычно не используют для привязки this

Коротко

call() в JavaScript нужен для немедленного вызова функции с указанным this и аргументами. Главное, что стоит запомнить: он похож на apply() и bind(), но работает по-своему, потому что вызывает функцию сразу и принимает аргументы отдельным списком.