call, apply, bind
Методы функций для управления this.
call
Вызывает функцию с указанным this и аргументами через запятую:
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const user = { name: 'Алиса' };
greet.call(user, 'Привет', '!'); // 'Привет, Алиса!'
apply
То же, но аргументы — массив:
greet.apply(user, ['Привет', '!']); // 'Привет, Алиса!'
bind
Возвращает новую функцию с привязанным this:
const boundGreet = greet.bind(user);
boundGreet('Привет', '!'); // 'Привет, Алиса!'
Можно привязать и аргументы:
const greetAlice = greet.bind(user, 'Привет');
greetAlice('!'); // 'Привет, Алиса!'
Потеря this
Без привязки:
const user = {
name: 'Алиса',
greet() {
return this.name;
},
};
const fn = user.greet;
fn(); // ошибка: this = undefined
С bind:
const fn = user.greet.bind(user);
fn(); // 'Алиса'
call для заимствования методов
Использовать метод массива на array-like:
function args() {
return Array.prototype.slice.call(arguments);
}
Или проще:
function args(...rest) {
return rest;
}
apply для spread
До появления spread:
Math.max.apply(null, [1, 2, 3]); // 3
Сейчас:
Math.max(...[1, 2, 3]);
bind в обработчиках
class Counter {
count = 0;
increment() {
this.count++;
}
}
const counter = new Counter();
// Так не работает
button.addEventListener('click', counter.increment);
// С bind
button.addEventListener('click', counter.increment.bind(counter));
// Или стрелочная
button.addEventListener('click', () => counter.increment());
bind возвращает новую функцию
function fn() {}
const bound = fn.bind(null);
fn === bound; // false
Каждый bind создаёт новую функцию. Учитывай в оптимизациях.
Двойной bind
Повторный bind не меняет this:
const bound1 = fn.bind(a);
const bound2 = bound1.bind(b); // this всё ещё a
Это фича: bind «запечатывает» контекст.
Современные альтернативы
- Стрелочные функции — для захвата
this - Классовые поля —
increment = () => {} - Стрелочные методы — автоматически захватывают
this
Практика: декоратор
function log(target, key, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`${key} вызван с`, args);
return original.apply(this, args);
};
return descriptor;
}
Здесь apply сохраняет this исходного вызова.
Практика: throttle
function throttle(fn, delay) {
let last = 0;
return function(...args) {
const now = Date.now();
if (now - last >= delay) {
last = now;
return fn.apply(this, args);
}
};
}
apply(this) передаёт this оригинала.
Когда использовать
- call — когда известны аргументы
- apply — когда аргументы в массиве (редко в современном коде)
- bind — когда нужна функция с фиксированным
this
Для большинства задач хватает стрелочных функций и bind.
Итоги
call— вызов сthisи аргументамиapply— вызов сthisи массивомbind— новая функция с привязаннымthisbind«запечатывает» контекст- Современные альтернативы — стрелочные функции
- Полезны в декораторах и обёртках