Что-то интересное в JavaScript — это то, как он обрабатывает функции. В JavaScript функции — это первоклассные данные, и их можно передавать так же, как и примитивные данные, такие как строки или массивы. Функции могут быть параметром другой функции, храниться в массиве или быть доступными из ключа объекта. Но при передаче функций по их контексту иногда можно потеряться. Вот тут-то и появляется метод bind().

Метод bind() в самом простом случае имеет следующий формат:

let boundFunc = func.bind(thisArg)

Параметр thisArg — это значение, которое будет использоваться в качестве параметра this в функции func при вызове функции. Другими словами, когда мы вызываем boundFunc, мы хотим использовать func в контексте thisArg.

Теперь для примера предположим, что у вас есть объект друга:

let friend = {
  name: "John",
  greetFriend: function(greeting = "Hello") {
    console.log(`${greeting}, ${this.name}`)
  }
}
friend.greetFriend()
    => Hello, John

Если вы вызовете функцию greetFriend немедленно, она будет работать, как мы и ожидали, записывая в журнал приветствие, которое мы ввели, и name объекта friend. Но если бы мы хотели сохранить функцию в новой переменной, это не сработало бы так же:

let greetJohn = friend.greetFriend
greetJohn("Good morning")
    => Good morning, undefined

В данном случае, потому что мы не вызываем функцию по отношению к объекту friend. Без контекста friend this в методе greetJohn пытается найти переменную с именем name в своем собственном контексте, в данном случае в глобальной области видимости. Вот тут-то и появляется bind(). Мы передаем в качестве аргумента bind контекст, в котором мы хотим использовать this. Вот так:

let greetJohn = friend.greetFriend.bind(friend)
greetJohn("Good evening")
    => Good evening, John

Мы также можем использовать это для привязки функции к контексту, отличному от того, из которого она пришла:

let newFriend = {
  name: "Jenny"
}
let greetJenny = friend.greetFriend.bind(newFriend)
greetJenny("Good afternoon")
    => Good afternoon, Jenny

Одним из наиболее важных способов использования bind является передача функции обратного вызова другой функции. Итак, если, например, мы хотим вызвать метод greetFriend для ведения журнала через две секунды, мы могли бы подумать, что можем использовать функцию setTimeout следующим образом:

setTimeout(friend.greetFriend, 2000)

Но, к сожалению, обратный вызов не сохраняет контекст, из которого он пришел. Приведенная выше строка соответствует:

let f = friend.greetFriend
setTimeout(f, 2000)
    => Hello, undefined

Один из способов обойти это — использовать функцию-оболочку:

setTimeout(() => friend.greetFriend(), 2000)
    => Hello, John

Но есть один возможный недостаток, который может возникнуть в этом случае. Если в течение двух секунд до запуска метода ключ greetFriend в friend будет изменен, метод setTimeout вызовет новый метод. Если вы используете bind, setTimeout будет использовать предварительно связанное значение, поэтому этот способ безопаснее:

setTimeout(friend.greetFriend.bind(friend, "Hey there"), 2000)
    => Hey there, John

Как вы можете видеть выше, метод bind также может принимать больше, чем просто параметр thisArg. Он также может принимать необязательные аргументы для подключения к функции, которую вы привязываете к thisArg. Таким образом, мы могли бы использовать bind в методе greetFriend по-другому:

let hiJohn = friend.greetFriend.bind(friend, "Hi")
hiJohn()
    => "Hi, John"

Другой способ использования необязательных аргументов bind — использовать их в функции, которой не нужен контекст, например:

function multiply(num1, num2) {
  return num1 * num2
}
let double = multiply.bind(null, 2)
double(5)
    => 10

В этом случае вызов bind создает новую функцию double, которая вызывает умножение. Поскольку нам не нужен никакой контекст для функции multiply, так как она не использует this, мы передаем null в качестве первого параметра bind. Поскольку мы зафиксировали 2 в качестве первого аргумента, double примет только один аргумент и передаст его для умножения на место num2.

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