What the heck is call(), bind() & apply() ?

Working with JavaScript “this” keyword can be tricky. Not knowing the background rules may end up with the famous “it works, but I don’t know why” or worse: “it doesn’t work and I don’t know why”. It’s good to know the theory before putting things into practice. call(), apply() and bind() methods can come in handy when setting the “this” value.

image.png

Basic rules worth remembering:

  • “this” always refers to an object.

  • “this” refers to an object which calls the function it contains.

  • In the global context “this” refers to either window object or is undefined if the strict mode is used

var person= { 
    firstName: "John",
    lastName: "Doe",
    dispalyDetails: function(){
        console.log(this.firstName+ " " + this.lastName);
    }
}

The above will work perfectly fine as long as we use it this way:

person.dispalyDetails(); // John Doe

But what if we want to borrow a method?

var anotherPersonDetails =  person.dispalyDetails;
anotherPersonDetails(); // "undefined undefined"

Well, this won’t work as the “this” will be now assigned to the global context which doesn’t have neither the firstName nor the lastName property. So, it's undefined.

The bind() Method to the rescue

For such cases we can use the ES5 bind() method of the Function.prototype property. This means bind() can be used by every single function.

var anotherPersonDetails = person.displayDetails.bind(person); 
anotherPersonDetails (); // John Doe

The bind() method creates a new function where “this” refers to the parameter in the parenthesis in the above case “person”. This way the bind() method enables calling a function with a specified “this” value. It's not invoked immediately like call() & apply().

What if we would like to pass an argument to the displayDetails function? We can use the bind() method again. The following argument of the bind() method will provide an argument to the function bind() is called on. In our case the person object.

Let me rewrite the person object:

var person = { 
    firstName: "John",
    lastName: "Doe",
    displayDetails: function(age){
        console.log("Hi I'm " + this.firstName + " " + this.lastName + " I'm "+ age + " years old");
    }
}

Example of passing arguments with bind():

var anotherPersonDetails = person.displayDetails.bind(person, 32); // Hi I'm John Doe, I'm 32 years old

call() and apply() are very similar they invoke a function immediately with a specified "this" context, and optional arguments. The only difference between call() and apply() is that call() requires the arguments to be passed in one-by-one, and apply() takes the arguments as an array.

Let's look at this example, this time there is a person object without the displayDetails method. displayDetails function is now defined in global scope.

var person= { 
    firstName: "John",
    lastName: "Doe"
}

function displayDetails(age) {
     console.log("Hi I'm " + this.firstName + " " + this.lastName + " I'm "+ age + " years old");
}

If we call this function directly without using call(), bind() or apply() method, it'll print undefined because here "this" refers to global window object and there is no such property firstName or lastName.

displayDetails(30); // Hi I'm undefined undefined I'm 30 years old

We can use the apply() function:

displayDetails.apply(person, [60]); // Hi I'm John Doe I'm 60 years old

// Or

displayDetails.call(person, 60); // Hi I'm John Doe I'm 60 years old

Note that when using the apply() method the parameter must be placed in an array. call() accepts both an array of parameters and a parameter itself. Both are great tools for borrowing functions in JavaScript.

bind(), call() and apply() methods can make your life easier when you need to set the value of ‘this’ explicitly. Hope the post was helpful.