Bind, call, and apply. Oh my!

or “why isn’t my setTimeout working?”


This is part three of a five part series. For more context see the previous two posts: Understanding Function Objects In JavaScript, and What is “this”?

So now that we have explained a little about what the “this” keyword is all about and what problems we can run into when “this” and function objects are allowed in the same language, lets explore some ways that we can pass function objects around while still maintaining their original “this” reference.

In Javascript, if we have a function that refers to the keyword “this”, we need to make sure that “this” will be what we expect it to be when we invoke the function. There are three properties on every function object in Javascript that exist to help mitigate this problem. These properties are the functions apply, call, and bind.

First I will attempt to explain the function apply and what it does. Before I get into any details, I think it is best to start out with some example code. I will re-use some code I used in the previous post and build on that. So here is the code from “What IS “this”?”:

var obj = {
x: 1,
fun: function(){ alert(this.x); }
};
var new_fun = obj.fun;
new_fun(); // runtime error!

So we have an object obj with the properties x, and fun. x is assigned to the value 1. fun is assigned to a function object that uses the this keyword to refer to its “sibling property” x. We then define a variable called “new_fun”. This variable is assigned to the same function object that obj.fun refers to. So if we try to invoke new_fun as it is, we will likely get a runtime error because the variable this will not be set to obj anymore. We can fix this problem by using either apply, call, or bind. Here is an example of using apply to make executing new_fun without runtime errors possible:

new_fun.apply(obj);

Function.prototype.apply is probably the most commonly used function of the three. Its function signature is as follows: apply(thisArg, [argsArray]). To re-iterate, apply is a function that is assigned as a property of every function object in javascript. This function, when invoked, will assign the keyword “this” to whatever is passed in as the first parameter. In our example above, we passed in obj as the first parameter. This assigns “this” to obj for this invocation of new_fun. An interesting thing we can do with apply is assign this to any arbitrary object we want. As long as the object we use has the properties that the function expects, it will work! Here’s an example:

var obj2 = { x:2 };
new_fun.apply(obj2);

We have just modified entirely what the “this” keyword refers to when new_fun is executing! After executing the above, we will be alerted 2 instead of 1. How exciting!

You may have noticed that I neglected to utilize or explain the second parameter given in apply’s function signature. So what is [argsArray] all about? It is a way for us to pass in any needed parameters to the function we are invoking with apply. Lets set up a little example:

var plus = function(b){ return this+b; };
plus.apply(1, [2]); // returns 3!

Here I defined a function plus that adds “this” and the parameter b together and returns the result. I then invoked plus with the apply function while setting thisArg to the value 1 and argsArray to the one element array [2]. This brings up two important points:

  1. With apply (and call and bind), we can assign “this” to be whatever we want! It can be a primitive value, an object, or even a function! It’s just another variable in the invoked function’s environment!
  2. The second argument given to apply MUST be an array. That’s just how it works.

The second point needs some further elaboration. Function.prototype.apply takes an array as its second input and applies each element of that array as a parameter of the function being invoked(this is also known as a splat). This is mostly useful for when you want to call apply and simply pass the arguments object along to the next function. To clarify, here is another example of using apply’s splatting:

var sum = function(a, b, c){
return a + b + c;
}
sum.apply(null, [1,2,3]); // returns 6

Note how I simply supplied null for the first argument this time. That is because the function sum as defined does not use the keyword “this”. I really didn’t need to use apply here, I just wanted to exemplify splatting.

Now that we understand how apply works, call and bind will come pretty easy. Call is just like apply, but it does not perform the splatting that apply does. Call can take any number of arguments and will supply them to the function you are calling it for. Here is a quick example using the sum function above:

sum.call(null, 1, 2, 3);

Call is usually used when we aren’t simply passing along the arguments object on the function we are invoking.

Finally, lets take a quick gander at what makes bind special:

var obj = {
x: 1,
fun: function(){ alert(this.x); }
};
var new_fun = obj.fun;
var obj2 = { x:2 };
var bound_new_fun = new_fun.bind(obj2);
bound_new_fun(); //alerts “2”

As you can see, bind takes a function object and produces a new function object that has its “this” variable bound to the given variable (in this case obj2). This allows us to later call this returned function and have it refer to obj2 as “this” when it is invoked. This can be really handy for calling an object method with a setTimeout or setInterval.

This is part three of a five part series (1, 2, 3, 4, 5). The next post will be Scopes in JavaScript.