← Назад к вопросам

Как работает call()?

1.0 Junior🔥 111 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает call()?

Метод call() в JavaScript — это один из самых важных механизмов для управления контекстом функции (значением this). Понимание этого метода критично для владения продвинутым JavaScript.

Базовое объяснение call()

Метод call() позволяет вызвать функцию с явно заданным контекстом this и аргументами:

// Синтаксис
// функция.call(контекст, аргумент1, аргумент2, ...)

const person = {
  firstName: "John",
  lastName: "Doe",
  greet: function() {
    return `Hello, ${this.firstName} ${this.lastName}`;
  }
};

console.log(person.greet()); // "Hello, John Doe"

// call() позволяет изменить контекст
const anotherPerson = {
  firstName: "Jane",
  lastName: "Smith"
};

// Вызываем метод person.greet в контексте anotherPerson
console.log(person.greet.call(anotherPerson)); // "Hello, Jane Smith"

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

call() передаёт аргументы функции после контекста:

function introduce(job, hobby) {
  console.log(`${this.name} works as ${job} and loves ${hobby}`);
}

const developer = { name: "Alice" };

// Первый параметр call() — контекст, остальные — аргументы функции
introduce.call(developer, "Frontend Developer", "coding");
// "Alice works as Frontend Developer and loves coding"

// Сравнение с apply() который передаёт аргументы массивом
introduce.apply(developer, ["Backend Developer", "debugging"]);
// "Alice works as Backend Developer and loves debugging"

call() для наследования методов

Одно из самых мощных применений call() — реализация наследования:

// Конструктор для класса Animal
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} издаёт звук`);
};

// Конструктор для класса Dog
function Dog(name, breed) {
  // Используем call() чтобы вызвать Animal конструктор
  // и установить свойства name в контексте Dog
  Animal.call(this, name);
  this.breed = breed;
}

// Наследование методов
Dog.prototype.speak = function() {
  console.log(`${this.name} лает и это ${this.breed}`);
};

const dog = new Dog("Rex", "Shepherd");
dog.speak(); // "Rex лает и это Shepherd"

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

call() позволяет использовать методы из одного объекта в контексте другого:

const arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };

// Массивные методы могут работать с array-like объектами
const result = Array.prototype.slice.call(arrayLike);
console.log(result); // ["a", "b", "c"]

// Преобразование arguments в массив
function myFunc(arg1, arg2, arg3) {
  const argsArray = Array.prototype.slice.call(arguments);
  console.log(argsArray); // [arg1, arg2, arg3]
}

// Или использовать spread оператор (современный подход)
function myFunc(...args) {
  console.log(args); // Уже массив
}

Практические примеры

// Пример 1: Делегирование контекста
const calculator = {
  value: 10,
  add: function(n) {
    return this.value + n;
  }
};

const anotherCalculator = { value: 20 };

console.log(calculator.add.call(anotherCalculator, 5)); // 25 (20 + 5)

// Пример 2: Работа с методами Object
const obj = { name: "Object" };

// Использование toString в контексте объекта
console.log(Object.prototype.toString.call(obj)); // "[object Object]"
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call(123)); // "[object Number]"

// Пример 3: React компонент с call()
class Parent {
  constructor() {
    this.name = "Parent";
  }
  
  sayName() {
    console.log(this.name);
  }
}

class Child extends Parent {
  constructor() {
    super();
    this.name = "Child";
  }
}

const child = new Child();
child.sayName(); // "Child"

// Вызвать parent метод
Parent.prototype.sayName.call(child); // Всё ещё "Child"

call() vs apply() vs bind()

function greet(greeting, name) {
  console.log(`${greeting}, ${name}! I am ${this.job}`);
}

const context = { job: "Developer" };

// call() — передаёт аргументы списком
greet.call(context, "Hi", "Alice");
// "Hi, Alice! I am Developer"

// apply() — передаёт аргументы массивом
greet.apply(context, ["Hello", "Bob"]);
// "Hello, Bob! I am Developer"

// bind() — создаёт новую функцию с сохранённым контекстом
const boundGreet = greet.bind(context, "Hey");
boundGreet("Charlie");
// "Hey, Charlie! I am Developer"

// Разница в использовании
// call — вызывает функцию сразу
// apply — вызывает функцию сразу
// bind — возвращает новую функцию для последующего вызова

call() в современном коде

В современном JavaScript call() встречается реже благодаря arrow функциям и classes:

// Старый способ
function OldClass() {
  this.value = 10;
  setTimeout(function() {
    console.log(this.value); // undefined (lost context)
  }, 1000);
}

// Исправление с call
function OldClass() {
  this.value = 10;
  const self = this;
  setTimeout(function() {
    console.log(self.value); // 10
  }, 1000);
}

// Современный способ — arrow функция сохраняет this
class ModernClass {
  constructor() {
    this.value = 10;
  }
  
  method() {
    setTimeout(() => {
      console.log(this.value); // 10 (this из ModernClass)
    }, 1000);
  }
}

Best Practices

  • Используйте call() когда нужно явно установить контекст
  • В современном коде предпочитайте arrow функции и классы
  • Помните что call() вызывает функцию сразу
  • bind() лучше если нужна отложенное выполнение
  • apply() удобна когда аргументы уже в массиве