Understanding “this” and Function.bind in Javascript

Max Lloyd
4 min readSep 4, 2016

Until recently I had never used Function.bind in Javascript, even thought i have been heavily coding in Javascript for a year and half. When I first encountered it, it looked somewhat spooky, and I stayed away from it, until now. Once I looked into how Function.bind worked I was amazed at how simple, useful and versatile it actually was.

Some examples!

If we head over to MDN we see Function.bind is described as such

The bind() method creates a new function that, when called, has its this keyword set to the provided value…

Now, what are a some of the ways we can take advantage of this function. Let me show you. (You can test out the code examples by opening the developer tools in your browser of choice and pasting the code snippets, or run them using Node.js)

function talk() {
console.log(this.talk)
}
var gandalf = {
talk: 'All we have to decide is what to do with the time that is given to us.'
};
talk();

The output:

I ran the code sample using Node.js

Why is the talk function logging undefined? Well, because we have not told which “this” context we want it to use when running the talk function. At the moment talk() is using the window object as its “this” context, and window.talk is being logged, which is undefined, instead of gandalf.talk if change the following line…

var boundTalk = talk.bind(gandalf);boundTalk();

The Output is:

That’s it! There is not much too it. Here we have told the compiler what “this” context the function should be run with, in this case it is the gandalf object. The correct text is now being logged!

Wait, I have heard about .bind, .call and .apply, What is the difference?

In the code example you can see that the returned function of .bind() is being assigned a variable called boundTalk, instead of just calling it directly. There are several ways to get around this.

  • You can call the returned function directly, without assigning it to a variable, like so: talk.bind(gandalf)();
  • You can use Function.call, which is very similar to Function.bind but instead of returning a function, it calls it directly with the provided “this” context: talk.call(gandalf, arg1, arg2). It also has the added benefit of being able to add additional arguments for the function to be called with. This can also be done using the method above, if you prefer that: talk.bind(gandalf)(arg1, arg2);
  • The last of the bunch is Function.apply, it is almost identical to Function.call but instead of passing in each argument separately like you would in Function.call, You can pass in an Array of arguments like so: talk.apply(gandalf, [arg1, arg2, …]). This can be useful for when you have an unspecified amount of arguments you want to pass to a function.

Pitfalls

In the example above it is fairly easy to debug why undefined is being logged, but there are other instances where identifying the issue is not so straight forward, especially when you are working with a large code base. Here is an example that I cooked up that illustrates the importance of understanding how to correctly use .bind, .call and .apply. This example uses .call but either of the two other methods could also have been used.

 function createDog (name, height, breed) {
return {
name: name,
height: height,
breed: breed,
energy: 100,
run: function() {
this.energy -= 10;
},
eat: function(food) {
this.energy += 10;
}
};
}
var flipper = createDog(‘Flipper’, ‘37cm’, ‘cocker spaniel’);
var william = createDog(‘William’, ‘85cm’, ‘St. Bernard’);
var dogs = [flipper, william];for (var i = 0; i < dogs.length; i++) {
var run = dogs[i].run;
run();
console.log(dogs[i].energy);
}

The output:

The dogs energy levels have not changed at all, you would expect them to be 90. But they remained at 100, this is because when we do
var run = dogs[i].run; Only the method is copied, not the context, when we do run() the energy levels of the dogs are not decremented, but rather the energy level of the window object, which is not what we want. There is an easy fix, you have to use the Function.call method when invoking the run function, like so: run.call(dogs[i]);. Now we are providing which context we want the function to be executed with. What is dangerous about this is that the compiler does not warn you about it at all, imagine if you had a similar scenario in a banking system!

Conclusion

Thanks for making it all the way to the end. I hope this gave you the same “Aha” moment i had when learning about this! It has been almost a year since I published anything, but i want to challenge my self to write at least one post a week!

Resources

--

--