bind / call / apply
В одной фразе: call и apply вызывают функцию немедленно с заданным this; bind возвращает новую функцию с “прошитым” this (и опционально — частичными аргументами). На собесе просят реализовать полифил bind и объяснить, почему bind нельзя перебить.
// call vs apply: разница только в способе передачи аргументовfunction introduce(greeting, punct) { return `${greeting}, I'm ${this.name}${punct}`;}const person = { name: 'Alice' };
introduce.call(person, 'Hello', '!'); // 'Hello, I'm Alice!'introduce.apply(person, ['Hi', '.']); // 'Hi, I'm Alice.'
// apply полезен когда аргументы уже в массиве;// сегодня заменяется spread: introduce.call(person, ...args)// bind: partial application + this-bindingfunction multiply(x, y) { return x * y; }
const double = multiply.bind(null, 2); // x=2 зафиксированdouble(5); // 10double(10); // 20
// Привязка метода к объекту (для addEventListener)class Button { constructor(label) { this.label = label; } click() { console.log(`Clicked: ${this.label}`); }}const btn = new Button('Submit');document.addEventListener('click', btn.click.bind(btn)); // this = btn всегда// bind "замораживает" this — его нельзя перебитьfunction show() { return this.x; }const bound = show.bind({ x: 1 });
bound.call({ x: 99 }); // 1 — call проигнорированbound.bind({ x: 99 })(); // 1 — второй bind не помогает
// Полифил Function.prototype.bind (упрощённый):Function.prototype.myBind = function (context, ...partial) { const fn = this; return function (...args) { return fn.apply(context, [...partial, ...args]); };};
const f = show.myBind({ x: 42 });f(); // 42Итог: bind создаёт новую функцию при каждом вызове — учитывай это при removeEventListener: нужно хранить результат bind, иначе снять обработчик не получится.