Кратко
call и apply вызывают функцию сразу с заданным this. Разница: call принимает аргументы по одному, apply — массивом. bind создаёт новую функцию с заранее заданным this (не вызывает сразу).
Подробно
Зачем нужен явный this?
Иногда нужно вызвать функцию «от имени» другого объекта:
function greet() {
console.log(Привет, ${this.name});
}
const user = { name: 'Анна' }; // greet.call(user) — вызвать greet, сделав this = user
call(thisArg, ...args): greet.call(user); // 'Привет, Анна'
greet.call(user, 'дополнительные', 'аргументы');
apply(thisArg, argsArray): greet.apply(user, ['дополнительные', 'аргументы']);
Разница call vs apply:
- call: аргументы через запятую: fn.call(obj, a, b, c)
- apply: аргументы массивом: fn.apply(obj, [a, b, c])
bind(thisArg, ...partialArgs): const boundGreet = greet.bind(user); boundGreet(); // 'Привет, Анна' — вызов в любой момент
bind НЕ вызывает функцию — он создаёт НОВУЮ функцию с фиксированным this.
Когда что использовать:
- call — вызов сразу с аргументами
- apply — вызов сразу с массивом аргументов
- bind — создание новой функции для будущего вызова
Ментальная модель
call — как сказать «прочитай это письмо, обращаясь к этому человеку» (сразу). apply — то же, но аргументы в конверте (массиве). bind — как создать шаблон письма с заранее вписанным именем (новая функция).
Примеры
**Самый простой:**
function greet(greeting) {
console.log(`${greeting}, ${this.name}!`);
}
const user = { name: 'Анна' };
greet.call(user, 'Привет'); // 'Привет, Анна!'
greet.apply(user, ['Здравствуй']); // 'Здравствуй, Анна!'call и apply вызывают функцию сразу с заданным this.
**Простой:**
function multiply(a, b) {
return a * b;
}
// call — аргументы по одному
console.log(multiply.call(null, 2, 3)); // 6
// apply — аргументы массивом
console.log(multiply.apply(null, [2, 3])); // 6
// bind — создаёт новую функцию
const double = multiply.bind(null, 2);
console.log(double(5)); // 10 (2 * 5)bind с частичными аргументами — удобный способ создать специализированную функцию.
**Реальный пример:**
const button = document.querySelector('#myButton');
// Проблема: this теряется в callback
// button.addEventListener('click', user.handleClick);
// this = button, не user!
// Решение 1: bind
// button.addEventListener('click', user.handleClick.bind(user));
// Решение 2: arrow function (предпочтительнее)
// button.addEventListener('click', () => user.handleClick());bind решает проблему потери this при передаче метода как callback.
Частые ошибки
**Неправильно:** Путать call и apply
**Почему:** call принимает аргументы по одному, apply — массивом.
**Правильно:** call(obj, a, b, c) vs apply(obj, [a, b, c]).
**Неправильно:** Думать, что bind вызывает функцию
**Почему:** bind создаёт НОВУЮ функцию. Для вызова нужен дополнительный ().
**Правильно:** bound() — вызов. bind() — только создание.
**Неправильно:** Использовать bind когда нужен arrow function
**Почему:** Arrow function проще: () => obj.method(). Не нужен bind.
**Правильно:** Для callback'ов предпочтительнее arrow functions.
Важно запомнить
- call(thisArg, ...args) — вызов сразу
- apply(thisArg, [args]) — вызов сразу с массивом
- bind(thisArg) — создаёт новую функцию
- bind с частичными аргументами — partial application
- Для callback'ов предпочтительнее arrow functions
Связь
Назад: Вы понимаете связывание this (JI4) — теперь у вас есть инструменты для управления им.
Вперёд: Следующий урок (JI6) — рекурсия и стек вызовов.