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

Для чего нужен call в JavaScript?

1.0 Junior🔥 201 комментариев
#JavaScript Core#Архитектура и паттерны

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Метод call() в JavaScript

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

Базовый синтаксис

function.call(thisArg, arg1, arg2, ...)

Параметры:

  • thisArg — объект, который будет контекстом this
  • arg1, arg2, ... — аргументы функции (передаются явно)

Простой пример

const user = {
  name: "Alice",
  age: 30
};

const admin = {
  name: "Bob",
  age: 35
};

function introduce() {
  console.log(${this.name}, мне ${this.age} лет`);
}

introduce.call(user);  // "Я Alice, мне 30 лет"
introduce.call(admin); // "Я Bob, мне 35 лет"

// Без call:
introduce(); // "Я undefined, мне undefined лет" (this = undefined в strict mode)

С передачей аргументов

function greet(greeting, punctuation) {
  console.log(greeting + " " + this.name + punctuation);
}

const person = { name: "Charlie" };

greet.call(person, "Hello", "!"); // "Hello Charlie!"
greet.call(person, "Hi", "?");     // "Hi Charlie?"

// Сравнение с bind и apply:
// call(thisArg, arg1, arg2, ...)
// apply(thisArg, [arg1, arg2, ...])
// bind(thisArg) → возвращает новую функцию

Практические применения

1. Заимствование методов из других объектов

const arrayMethods = {
  sum() {
    return this.reduce((a, b) => a + b, 0);
  }
};

// Используем метод массива для array-like объекта
const numbers = [1, 2, 3, 4, 5];
const result = arrayMethods.sum.call(numbers);
console.log(result); // 15

// Реальный пример: Array.prototype.slice с array-like объектом
function myFunction() {
  const args = Array.prototype.slice.call(arguments);
  console.log(args);
}
myFunction(1, 2, 3); // [1, 2, 3]

2. Вызов родительского метода в наследовании

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(this.name + " makes a sound");
};

function Dog(name, breed) {
  Animal.call(this, name); // Вызываем родительский constructor
  this.breed = breed;
}

Dog.prototype.speak = function() {
  console.log(this.name + " barks");
};

const dog = new Dog("Rex", "Labrador");
console.log(dog.name);  // "Rex"
console.log(dog.breed); // "Labrador"

3. В методах класса

class Service {
  getData() {
    return fetch('/api/data').then(r => r.json());
  }
}

class ExtendedService extends Service {
  async getDataWithCache() {
    // Явно вызываем метод родительского класса
    const data = await super.getData();
    // Кеширование логика
    return data;
  }
}

4. Функции высшего порядка

function makeMultiplier(multiplier) {
  return function(value) {
    return value * multiplier;
  };
}

const double = makeMultiplier(2);
const triple = makeMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

// С call и контекстом:
const calculator = {
  multiplier: 10,
  multiply: function(value) {
    return value * this.multiplier;
  }
};

const number = 5;
console.log(calculator.multiply.call(calculator, number)); // 50

call vs apply vs bind

const user = { name: "Diana" };

function introduce(greeting, punctuation) {
  console.log(greeting + " " + this.name + punctuation);
}

// call: аргументы перечисляются
introduce.call(user, "Hi", "!"); // "Hi Diana!"

// apply: аргументы в массиве
introduce.apply(user, ["Hello", "?"]); // "Hello Diana?"

// bind: возвращает новую функцию
const greet = introduce.bind(user);
greet("Hey", "~"); // "Hey Diana~"

// bind с частичным применением (currying)
const greetDiana = introduce.bind(user, "Welcome");
greetDiana("!"); // "Welcome Diana!"

Реальные примеры в React

Работа с обработчиками событий (class components):

class Button extends React.Component {
  constructor(props) {
    super(props);
    // Привязываем this к методу
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    console.log(this.state); // Работает благодаря bind
  }
  
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

// Или с call в inline:
class AltButton extends React.Component {
  handleClick() {
    console.log(this.props);
  }
  
  render() {
    return (
      <button onClick={() => this.handleClick.call(this)}>
        Click
      </button>
    );
  }
}

Использование методов массива

// Преобразование array-like объекта
function collectArgs() {
  const args = Array.prototype.slice.call(arguments);
  return args.map(arg => arg * 2);
}

collectArgs(1, 2, 3); // [2, 4, 6]

// Или с современным синтаксисом:
function collectArgsModern() {
  const args = [...arguments];
  return args.map(arg => arg * 2);
}

Когда использовать

Используй call когда:

  • Нужно вызвать функцию с конкретным контекстом
  • Передаёшь несколько аргументов (apply лучше для массивов)
  • Работаешь с наследованием
  • Заимствуешь методы из других объектов

Используй apply когда:

  • Аргументы уже в массиве
  • Работаешь с переменным количеством аргументов

Используй bind когда:

  • Нужна новая функция с привязанным this
  • Передаёшь callback, который потом вызовется
  • Нужно частичное применение (currying)

Современный подход

В современном JavaScript часто используют стрелочные функции, которые не требуют call:

// Старый способ
class Component {
  constructor() {
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    console.log(this);
  }
}

// Новый способ (стрелочная функция)
class Component {
  handleClick = () => {
    console.log(this); // this из class scope
  }
}

Но понимание call() остаётся важным для:

  • Работы с наследованием в constructor functions
  • Работы с legacy кодом
  • Оптимизации (call быстрее, чем создавать новую функцию с bind)
  • Интервью и глубокого понимания JavaScript