← Назад к вопросам

Что будет при bind двух разных контекстов функции?

1.7 Middle🔥 251 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ на вопрос о двойном bind в JavaScript

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

Механизм работы bind()

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

const obj1 = { name: 'Контекст 1' };
const obj2 = { name: 'Контекст 2' };

function showName() {
    console.log(this.name);
}

// Первый bind
const boundOnce = showName.bind(obj1);

// Второй bind на уже привязанной функции
const boundTwice = boundOnce.bind(obj2);

// Вызов
boundTwice(); // Выведет: "Контекст 2"

Почему второй bind перезаписывает первый

  1. bind не мутирует исходную функцию, а возвращает новую обёртку
  2. При повторном вызове bind создаётся ещё одна обёртка, но она привязывается к новому контексту, игнорируя предыдущий
  3. Это происходит потому, что bind устанавливает внутреннее свойство [[BoundThis]] у создаваемой функции, и при повторном bind создается новая функция с новым значением [[BoundThis]]
// Более сложный пример с аргументами
function sum(a, b) {
    console.log(this.prefix + (a + b));
    return a + b;
}

const context1 = { prefix: 'Результат: ' };
const context2 = { prefix: 'Сумма = ' };

// Первый bind с частичным применением аргументов
const bound1 = sum.bind(context1, 10);

// Второй bind с другим контекстом
const bound2 = bound1.bind(context2, 20);

bound2(); 
// Выведет: "Сумма = 30"
// Контекст context1 игнорируется, используется context2

Технические детали реализации

С точки зрения спецификации ECMAScript:

  • Каждая bound function имеет внутренние слоты:
    • [[BoundTargetFunction]] - целевая функция
    • [[BoundThis]] - привязанное значение this
    • [[BoundArguments]] - предустановленные аргументы
  • При вызове bind на уже привязанной функции создаётся новая bound function, которая ссылается на предыдущую bound function как целевую, но с новым [[BoundThis]]
// Демонстрация цепочки
const objA = { x: 'A' };
const objB = { x: 'B' };
const objC = { x: 'C' };

function test() {
    return this.x;
}

const fnA = test.bind(objA);
const fnB = fnA.bind(objB);
const fnC = fnB.bind(objC);

console.log(fnA()); // "A"
console.log(fnB()); // "B" (не "A"!)
console.log(fnC()); // "C" (не "B" и не "A"!)

// Проверка длины цепочки
console.log(fnA === test); // false
console.log(fnB === fnA); // false
console.log(fnC === fnB); // false

Практические последствия и рекомендации

Важные аспекты:

  • Двойной bind может быть источником ошибок, если разработчик ожидает комбинации контекстов
  • Предустановленные аргументы первого bind сохраняются, но контекст - нет
  • Невозможно "отменить" или "переопределить" bind частично
// Пример с сохранением аргументов первого bind
function multiply(a, b, c) {
    console.log(this.name, a * b * c);
}

const ctx1 = { name: 'Первый' };
const ctx2 = { name: 'Второй' };

const firstBind = multiply.bind(ctx1, 2, 3);
const secondBind = firstBind.bind(ctx2, 4);

secondBind(); // Выведет: "Второй 24"
// Контекст ctx1 утерян, но аргументы 2 и 3 сохранились

Вывод

Повторный вызов bind() всегда приводит к полной замене контекста this на новый, при этом:

  • Предыдущие привязки контекста теряются
  • Предустановленные аргументы сохраняются и накапливаются
  • Создается новая функция каждый раз при вызове bind()

Понимание этого поведения критически важно для корректной работы с обработчиками событий, коллбэками и другими сценариями, где требуется контроль над контекстом выполнения в JavaScript.