Skip to main content

Метод Function.prototype.bind

Function.prototype.bind повертає нову функцію з назавжди прив'язаним контекстом this, а не викликає функцію одразу. Це третій із «методів керування контекстом» поряд із call та apply, і саме відкладений виклик робить його особливим.

Теорія

TL;DR

  • bind створює нову функцію, у якої this зафіксований назавжди.
  • Оригінальна функція не змінюється: bind повертає окрему копію.
  • Можна заздалегідь зафіксувати частину аргументів (partial application).
  • Функція не виконується одразу, її викликають пізніше вручну.
  • Прив'язаний this неможливо перевизначити через call або apply.
  • Виняток: виклик через new ігнорує прив'язаний контекст.

Швидкий приклад

javascript
function greet() { console.log(`Привіт, я ${this.name}`); } const user = { name: 'Maria' }; const sayHi = greet.bind(user); sayHi(); // Привіт, я Maria

Тут sayHi це нова функція, у якої this назавжди прив'язаний до user.

Синтаксис і що саме повертає bind

javascript
func.bind(thisArg, arg1, arg2, ...)
  • thisArg це значення, яке стане this всередині функції під час виклику;
  • arg1, arg2, ... це аргументи, які будуть підставлені «за замовчуванням»;
  • повертається нова функція, яку можна викликати пізніше.

Отже, bind створює нову функцію, у якої:

  • назавжди закріплений контекст this;
  • можна частково зафіксувати аргументи;
  • сама функція не виконується одразу, а повертається для виклику згодом.

Втрата контексту в callback

Найчастіше bind потрібен саме для того, щоб зберегти this під час передачі методу як callback. Коли метод передають за посиланням, зв'язок з об'єктом губиться:

javascript
const user = { name: 'Maria', sayHi() { console.log(`Привіт, я ${this.name}`); } }; setTimeout(user.sayHi, 1000); // this загублений -> "Привіт, я undefined" setTimeout(user.sayHi.bind(user), 1000); // правильно -> "Привіт, я Maria"

Те саме стосується обробників подій і колбеків у методах на кшталт map, forEach, then.

Часткове застосування аргументів

bind дозволяє «передзадати» не лише контекст, а й частину аргументів:

javascript
function introduce(city, job) { console.log(`Я ${this.name} з міста ${city}, працюю як ${job}`); } const person = { name: 'Maria' }; const introduceMaria = introduce.bind(person, 'Kyiv'); introduceMaria('Frontend-розробник'); // Я Maria з міста Kyiv, працюю як Frontend-розробник

Тут перший аргумент ('Kyiv') зафіксовано заздалегідь, а решту передають під час виклику.

Контекст при цьому потрібен не завжди, тож для чистого partial application передають null:

javascript
function multiply(a, b) { return a * b; } const double = multiply.bind(null, 2); console.log(double(5)); // 10

bind створив нову функцію, де a = 2 зафіксовано, і вона чекає тільки на другий аргумент b.

Відмінність від call і apply

МетодЩо робитьКоли викликаєтьсяЯк передаються аргументи
callВикликає функцію із заданим thisОдразуЧерез кому
applyТе саме, але аргументи масивомОдразуМасивом
bindПовертає нову функцію з «прив'язаним» thisПізнішеЧерез кому

Особливості bind і поведінка з new

  1. bind не змінює оригінальну функцію, а повертає нову копію.
  2. «Прив'язаний» this змінити вже не можна, навіть через call або apply.
  3. Якщо прив'язану функцію викликати як конструктор (new), this всередині неї буде новим об'єктом, а не прив'язаним контекстом.
javascript
function User(name) { this.name = name; } const BoundUser = User.bind({ name: 'Maria' }); const u = new BoundUser('Alice'); console.log(u.name); // Alice, контекст прив'язки ігнорується при new

Тобто при new у bind є особливість: пріоритет має конструктор, а не прив'язаний this.

Підсумок:

ВластивістьОпис
Що робитьПрив'язує контекст this і/або частину аргументів
Що повертаєНову функцію
Коли викликаєтьсяПізніше (вручну)
Чи можна змінити контекст потімНі
Часткове застосуванняТак
Часто використовується дляCallbacks, обробників подій, React-компонентів

Типові помилки

  • Чекають, що bind викличе функцію. Він лише повертає нову функцію; без пари дужок нічого не станеться.
  • Не зберігають результат. user.sayHi.bind(user); окремим рядком безглуздий: оригінал не змінюється, треба присвоїти результат.
  • Намагаються перебити прив'язку через call. Після bind контекст зафіксований, і bound.call(other) його не змінить.
  • Прив'язують у кожному рендері. onClick={this.handle.bind(this)} створює нову функцію щоразу і ламає мемоізацію; краще прив'язати один раз або використати стрілкову функцію.
  • Прив'язують стрілкову функцію. У стрілок немає власного this, тому bind на них не впливає.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.