W3docs

Метод bind() в JavaScript

Привязка функций в JavaScript: почему методы теряют `this` при передаче в setTimeout или как колбэк, как работает func.bind(), частичное применение и отличия bind от стрелочных функций.

В JavaScript значение this внутри метода определяется в момент вызова функции, а не в момент её написания. Стоит отделить метод от объекта — например, передав его как колбэк или в setTimeout — и он забудет, к какому объекту принадлежал. Привязка функции — это способ решить проблему: она навсегда фиксирует this на выбранном объекте, так что метод ведёт себя одинаково независимо от места вызова.

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

Проблема «потери this»

Метод работает корректно при вызове в форме object.method(), так как this устанавливается в объект слева от точки. Но если передать тот же метод куда-то ещё, точки уже нет — и this теряется.

javascript— editable

Второй вызов выводит Hello, undefined!, потому что runLater вызвал callback() как обычную функцию — без объекта перед точкой, поэтому this уже не является user. (В строгом режиме this равно undefined, и обращение к this.firstName вызвало бы TypeError.)

То же самое происходит с setTimeout — он сохраняет функцию и вызывает её позже самостоятельно, без привязки к какому-либо объекту:

javascript— editable

Подробнее о том, как определяется this внутри методов, читайте в разделе Методы объекта, «this».

Решение с помощью func.bind()

Метод func.bind(thisArg) возвращает новую функцию, в которой this навсегда установлен в thisArg. Исходная функция не изменяется — вы получаете связанную копию.

javascript— editable

Распространённый паттерн — сохранить привязанную версию обратно в объект, чтобы любую ссылку на неё можно было безопасно передавать:

javascript— editable

Привязка происходит только один раз

После привязки функции this фиксируется навсегда. Повторный вызов bind на результате ничего не даёт — вторая привязка игнорируется.

javascript— editable

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

bind принимает аргументы после thisArg, и они передаются в исходную функцию перед любыми последующими аргументами. Это позволяет создавать специализированные функции из более общих — такой подход называется частичным применением.

javascript— editable

Можно одновременно предустановить и this, и аргументы:

javascript— editable

bind и стрелочные функции

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

javascript— editable

Как выбрать подходящий вариант:

  • Используйте стрелочную функцию, чтобы захватить текущий this встроенно — особенно в колбэках, где не нужна отдельная переиспользуемая функция.
  • Используйте bind, когда нужна самостоятельная функция с фиксированным this для передачи в другое место, или когда требуется также предустановить аргументы. В отличие от стрелочной функции, привязанную функцию можно сохранить, переиспользовать и передавать по имени.

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

Когда это используется?

  • При передаче метода в обработчик событий, setTimeout/setInterval, Promise.then или такие методы array как forEach.
  • При создании специализированных функций из общих с помощью частичного применения (например, bind(null, presetArg)).
  • Всякий раз, когда метод должен продолжать работать после отделения от своего объекта.

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

Практика

Практика
Какие из следующих утверждений точно описывают поведение и использование привязки функций в JavaScript?
Какие из следующих утверждений точно описывают поведение и использование привязки функций в JavaScript?
Was this page helpful?