Что такое bind в JavaScript и как им пользоваться для привязки контекста?
Что проверяют
Понимаете ли вы, как в JavaScript определяется this, и можете ли объяснить, почему метод, переданный колбэком, теряет контекст. Следом почти всегда просят сравнить bind с call и apply, а иногда написать полифил.
Как отвечать
this в обычной функции задаётся не местом объявления, а способом вызова. obj.method() получает obj, а та же функция, сохранённая в переменную и вызванная как f(), в строгом режиме получит undefined. Модули и классы всегда в строгом режиме. В addEventListener браузер подставит в this сам элемент, в setTimeout глобальный объект, но не ваш obj.
fn.bind(thisArg, ...args) не вызывает функцию, а возвращает новую, связанную:
- контекст фиксируется навсегда: повторный
bind,callиapplyего уже не поменяют; - частичное применение: аргументы после
thisArgподставляются первыми,mul.bind(null, 2)превращает умножение в удвоение; - new сильнее bind: при вызове через
newпривязанныйthisигнорируется, а заранее переданные аргументы остаются; - стрелочные функции: своего
thisу них нет, он берётся из внешней области, иbindна него не влияет; - метаданные:
nameполучает префиксbound,lengthуменьшается на число привязанных аргументов.
Отличие от соседей простое: call(ctx, a, b) и apply(ctx, [a, b]) вызывают функцию сразу, bind откладывает вызов.
Во фронтенде bind встречается в обработчиках событий, таймерах и классовых компонентах React с this.handleClick = this.handleClick.bind(this) в конструкторе. Сейчас чаще пишут поле класса со стрелкой, handleClick = () => {...}, эффект тот же.
Где спотыкаются
Вызывают bind прямо при подписке: el.addEventListener("click", this.onClick.bind(this)). Каждый вызов создаёт новую функцию, и removeEventListener с тем же выражением ничего не снимет. Связанную функцию нужно сохранить.
Пишут bind в JSX, например onClick={this.save.bind(this)}. На каждый рендер получается новая ссылка, и React.memo у дочернего компонента перестаёт помогать.
Пытаются привязать контекст к стрелочной функции или ждут, что второй bind заменит первый. В обоих случаях this остаётся прежним.