JavaScript’s bind() Method
Something interesting about JavaScript is the way it treats functions. In JavaScript functions are first-class data and they can be passed around the same way as primitive data, like strings or arrays. Functions can be a parameter of another function, be stored in an array or be accessible from an object key. But when passing functions around their context can sometimes get lost. This is where the bind()
method comes in.
The bind()
method, at it’s simplest, has this format:
let boundFunc = func.bind(thisArg)
The thisArg
parameter is the value to be used as the this
parameter in the function func
when the function is called. Another way to say this is that, when we invoke boundFunc
we want to use func
with the context of thisArg
.
Now for an example, lets say you have a friend object:
let friend = {
name: "John",
greetFriend: function(greeting = "Hello") {
console.log(`${greeting}, ${this.name}`)
}
}
friend.greetFriend()
=> Hello, John
If you invoke the greetFriend
function immediately, it works as we expect, logging with the greeting we input and the name
of the friend
object. But if we wanted to save the function in a new variable it wouldn’t work the same way:
let greetJohn = friend.greetFriend
greetJohn("Good morning")
=> Good morning, undefined
In this case, because we are not calling the function in relation to the friend
object. Without the context of friend
, the this
in the greetJohn
method is trying to find a variable called name
in it’s own context, in this case the global scope. This is where bind()
comes in. We pass as an argument to bind
the context we want it to use this
on. Like so:
let greetJohn = friend.greetFriend.bind(friend)
greetJohn("Good evening")
=> Good evening, John
We can also use this to bind the function to a different context than the one it came from:
let newFriend = {
name: "Jenny"
}
let greetJenny = friend.greetFriend.bind(newFriend)
greetJenny("Good afternoon")
=> Good afternoon, Jenny
One of the most important ways in which bind
is useful is when you are passing a callback function to another function. So if, for example, we wanted to call to call the greetFriend
method to log after two seconds we would think we could use the setTimeout
function likes so:
setTimeout(friend.greetFriend, 2000)
But unfortunately, a callback doesn’t keep the context it came from. The above line equates to:
let f = friend.greetFriend
setTimeout(f, 2000)
=> Hello, undefined
One way to get around this is to use a wrapper function:
setTimeout(() => friend.greetFriend(), 2000)
=> Hello, John
But there is one possible flaw that could occur in this case. If within the two seconds before the method fires off, the greetFriend
key in friend
is changed, the setTimeout
method will call the new method. If you use bind
, setTimeout
will use the pre-bound value, so this way is safer:
setTimeout(friend.greetFriend.bind(friend, "Hey there"), 2000)
=> Hey there, John
As you can see above, the bind
method can also take more than just the thisArg
parameter. It can also take optional arguments to plug into the function you are binding to thisArg
. So another way we could use bind
on the greetFriend
method is like so:
let hiJohn = friend.greetFriend.bind(friend, "Hi")
hiJohn()
=> "Hi, John"
Another way you can use the optional arguments of bind
is to use it on a function that doesn’t need context, for example:
function multiply(num1, num2) {
return num1 * num2
}
let double = multiply.bind(null, 2)
double(5)
=> 10
In this case, the call to bind
creates a new function double
that makes calls to multiply. Because we don’t need any context for the multiply
function since it doesn’t use this
, we pass null
in as the first parameter of bind
. Because we fixed 2
as the first argument, double will only take one argument and pass it to multiply in the num2
place.
Ultimately, bind()
is a good method to be familiar with in JavaScript. Given the fact that JavaScript uses functions so often and in so many ways, there are many possibilities for a function’s context to get lost. If you know how to use bind()
correctly you can always make sure that functions are being used in the context you intend them to be.