Чем отличаются `call`, `apply` и `bind`?
call и apply немедленно вызывают функцию с заданным this, отличаясь лишь способом передачи аргументов: call — через запятую, apply — массивом. bind возвращает новую функцию с привязанным this, не вызывая её сразу.Общая идея
Все три метода позволяют явно задать контекст выполнения функции — то есть указать, чем будет являться this внутри неё. Они определены на Function.prototype и доступны у любой функции.
call
Вызывает функцию немедленно. Первый аргумент — контекст (this), остальные — аргументы функции, перечисленные через запятую.
function greet(greeting, punctuation) {
// this.name берётся из переданного контекста
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const user = { name: 'Алексей' };
greet.call(user, 'Привет', '!'); // Привет, Алексей!
apply
Работает идентично call, но аргументы функции передаются вторым параметром в виде массива (или массивоподобного объекта). Удобен, когда аргументы уже собраны в массив.
greet.apply(user, ['Здравствуйте', '.']); // Здравствуйте, Алексей.
// Классический приём — нахождение максимума в массиве
const numbers = [3, 1, 4, 1, 5, 9];
const max = Math.max.apply(null, numbers); // 9
// Сегодня чаще используют spread: Math.max(...numbers)
bind
Не вызывает функцию. Возвращает новую функцию с намертво привязанным this (и, опционально, с частично зафиксированными аргументами — карринг). Привязанный this нельзя переопределить повторным call/apply/bind.
const greetAlexey = greet.bind(user, 'Привет');
greetAlexey('!'); // Привет, Алексей!
greetAlexey('?'); // Привет, Алексей?
// Типичный случай — сохранение контекста для колбэка
class Timer {
constructor() {
this.seconds = 0;
// без bind this внутри tick будет undefined (strict) или window
setInterval(this.tick.bind(this), 1000);
}
tick() {
this.seconds++;
}
}
Сравнительная таблица
call | apply | bind | |
|---|---|---|---|
| Вызов | немедленный | немедленный | отложенный |
| Аргументы | перечислением | массивом | перечислением (частично) |
| Возвращает | результат функции | результат функции | новую функцию |
Переопределить this потом | можно | можно | нельзя |
Когда что использовать
call— одноразовый вызов с известными аргументами и нужным контекстом.apply— аргументы уже в массиве или нужно передать динамический набор.bind— колбэки, обработчики событий, передача метода как функции первого класса, частичное применение аргументов.
Важно про стрелочные функции
Стрелочные функции не имеют собственного this — все три метода не могут изменить их контекст. bind вернёт обёртку, но this внутри стрелки останется тем, каким был при создании.
Что хочет услышать интервьюер
Кандидат чётко объясняет разницу: call/apply вызывают функцию немедленно, bind — нет
Понимает разницу в передаче аргументов между call (перечислением) и apply (массивом)
Знает, что bind возвращает новую функцию и фиксирует this навсегда
Может назвать практические сценарии применения каждого метода (колбэки, spread-замена apply и т.д.)
Упоминает, что стрелочные функции игнорируют все три метода в плане this
Пример: call, apply и bind на одном примере
interface User {
name: string;
}
function introduce(role: string, company: string): string {
// this типизируется через ThisParameterType
return `Я ${(this as User).name}, ${role} в ${company}`;
}
const alice: User = { name: 'Алиса' };
// call — аргументы через запятую, немедленный вызов
console.log(introduce.call(alice, 'разработчик', 'PurpleSchool'));
// 'Я Алиса, разработчик в PurpleSchool'
// apply — аргументы массивом, немедленный вызов
console.log(introduce.apply(alice, ['тимлид', 'PurpleSchool']));
// 'Я Алиса, тимлид в PurpleSchool'
// bind — возвращает новую функцию, this зафиксирован
const introduceAlice = introduce.bind(alice);
console.log(introduceAlice('ментор', 'PurpleSchool'));
// 'Я Алиса, ментор в PurpleSchool'
// Частичное применение через bind
const introduceAsDev = introduce.bind(alice, 'разработчик');
console.log(introduceAsDev('Yandex'));
// 'Я Алиса, разработчик в Yandex'
// Стрелочная функция — bind не меняет this
const arrow = () => (globalThis as unknown as { tag: string }).tag ?? 'global';
const bound = arrow.bind({ tag: 'игнорируется' });
console.log(bound()); // 'global' — this стрелки неизменяем
Типичные ошибки
Путают порядок: говорят, что apply принимает аргументы через запятую, а call — массивом
Считают, что bind вызывает функцию немедленно, а не возвращает новую
Не знают, что повторный bind или call на результат bind не меняет this
Забывают о частичном применении аргументов (карринге) через bind
Не упоминают стрелочные функции и их игнорирование явного контекста


