Bind: примеры (JAVASCRIPT)

Привязка контекста в JavaScript: метод bind
Раздел: Функции, Контекст выполнения
bind(thisArg, ...args): function

Основы метода bind

Метод bind() в JavaScript создает новую функцию, которая при вызове имеет заданное значение this и, возможно, начальные аргументы. Этот метод используется для явной привязки контекста выполнения.

Применение bind() актуально в ситуациях, когда необходимо гарантировать, что функция будет вызвана в определенном контексте, независимо от места её последующего вызова. Часто это требуется при работе с методами объектов, передаваемыми в качестве колбэков, или при использовании методов, заимствованных у других объектов.

Синтаксис метода: function.bind(thisArg[, arg1[, arg2[, ...]]])

  • thisArg: Значение, которое передается как параметр this целевой функции при вызове привязанной функции. Если метод используется с оператором new, это значение игнорируется.
  • arg1, arg2, ...: Необязательные аргументы, которые предварительно добавляются к аргументам привязанной функции при её вызове. Это называется частичным применением (каррированием).

Возвращаемое значение: метод bind() возвращает новую функцию (копию оригинальной), с привязанным контекстом this и, возможно, начальными аргументами. Оригинальная функция не изменяется.

Примеры использования bind

Простейшая привязка контекста:

const user = {
  name: 'Алексей',
  greet() { console.log(`Привет, ${this.name}!`); }
};

const greetFunc = user.greet;
greetFunc(); // Ошибка: this.name undefined

const boundGreet = user.greet.bind(user);
boundGreet(); // Привет, Алексей!
Привет, Алексей!

Частичное применение аргументов:

function multiply(a, b) {
  return a * b;
}

const double = multiply.bind(null, 2);
console.log(double(5)); // 10
console.log(double(10)); // 20
10
20

Использование с конструктором (значение thisArg игнорируется):

function Car(model) {
  this.model = model;
}

const BoundCar = Car.bind({ dummy: 'ignored' });
const myCar = new BoundCar('Toyota');
console.log(myCar.model); // Toyota
console.log(myCar.dummy); // undefined
Toyota
undefined

Похожие методы в JavaScript

Для управления контекстом выполнения существуют методы call() и apply().

  • call(thisArg, arg1, ...): Немедленно вызывает функцию с заданным контекстом this и отдельными аргументами. Подходит для однократного вызова.
  • apply(thisArg, [argsArray]): Немедленно вызывает функцию с заданным контекстом this и массивом аргументов. Удобен, когда аргументы представлены в виде массива.

Сравнение: bind() создает новую функцию для отложенного вызова, тогда как call() и apply() выполняют вызов немедленно. Для постоянной привязки контекста, особенно в колбэках, предпочтительнее bind(). Стрелочные функции также автоматически связывают контекст лексически, что часто делает их более удобной альтернативой.

Аналоги в других языках

В различных языках существуют свои механизмы для привязки контекста или частичного применения.

Python (functools.partial): Создает новую функцию с частично примененными аргументами, но не управляет аналогом this явно.

from functools import partial

def multiply(x, y):
    return x * y
double = partial(multiply, 2)
print(double(5))  # 10
10

PHP (Closure::bind, Closure::call): Позволяет привязать объект и область видимости к анонимной функции.

class User {
    private $name = 'Мария';
}
$greet = function() { return 'Привет, ' . $this->name; };
$boundGreet = Closure::bind($greet, new User(), 'User');
echo $boundGreet();
Привет, Мария

C++ (std::bind): Осуществляет частичное применение и привязку аргументов, включая указатели на методы объектов.

Отличия от JS: в JavaScript bind() тесно связан с динамическим this, что не имеет прямого аналога в языках с другим моделированием методов (например, Python, где self явно передается).

Распространенные ошибки

1. Потеря контекста при использовании метода объекта в качестве колбэка без привязки.

const button = {
  title: 'Кнопка',
  click() { console.log(this.title); }
};

// Без bind контекст потеряется
setTimeout(button.click, 100); // Выведет undefined
// Правильно:
setTimeout(button.click.bind(button), 200); // Кнопка
undefined
Кнопка

2. Попытка перепривязать уже привязанную функцию. Контекст первой привязки изменить нельзя.

function logThis() { console.log(this.id); }
const obj1 = { id: 1 };
const obj2 = { id: 2 };

const bound = logThis.bind(obj1);
bound(); // 1

const rebound = bound.bind(obj2);
rebound(); // 1 (все еще привязано к obj1)
1
1

3. Непонимание, что bind создает новую функцию, а не меняет исходную.

function original() {}
const bound = original.bind({});
console.log(original === bound); // false
false

Изменения в последних версиях

Спецификация метода Function.prototype.bind была стандартизирована в ECMAScript 5 (ES5) и с тех пор остается стабильной. В более поздних версиях ECMAScript (ES6/ES2015 и далее) не было внесено изменений в поведение или сигнатуру этого метода.

Однако с появлением стрелочных функций в ES6 у разработчиков появилась более лаконичная альтернатива для сохранения лексического контекста this, что уменьшило необходимость частого использования bind() в некоторых сценариях, особенно при работе с колбэками внутри методов класса.

Расширенные примеры применения

Привязка контекста для метода, используемого как обработчик события в классе (до стрелочных функций):

Пример javascript
class ToggleButton {
  constructor() {
    this.isOn = false;
    this.button = document.createElement('button');
    // Без bind this будет указывать на DOM-элемент
    this.button.addEventListener('click', this.toggle.bind(this));
  }
  toggle() {
    this.isOn = !this.isOn;
    console.log(this.isOn);
  }
}
const btn = new ToggleButton(); // При клике логирует true/false

Каррирование (последовательное применение аргументов):

Пример javascript
function createUrl(scheme, domain, path) {
  return `${scheme}://${domain}/${path}`;
}
const createHttpsUrl = createUrl.bind(null, 'https');
const createMySiteUrl = createHttpsUrl.bind(null, 'mysite.ru');

console.log(createMySiteUrl('page')); // https://mysite.ru/page
console.log(createMySiteUrl('about')); // https://mysite.ru/about
https://mysite.ru/page
https://mysite.ru/about

Имитация приватных методов через замыкание и bind (устаревший паттерн):

Пример javascript
function Counter() {
  let privateCount = 0;
  function privateIncrement() {
    privateCount++;
    console.log(privateCount);
  }
  // Привязываем приватную функцию, но контекст не важен
  this.publicIncrement = privateIncrement.bind(this);
}
const c = new Counter();
c.publicIncrement(); // 1
c.publicIncrement(); // 2
// console.log(c.privateCount); // undefined
1
2

JS bind function comments

En
Bind Creates a new function that, when called, has its `this` keyword set to the provided value