loading...
Cover image for Truly Understand Bind, Call & Apply

Truly Understand Bind, Call & Apply

bhagatparwinder profile image Parwinder πŸ‘¨πŸ»β€πŸ’» ・3 min read

Bind

The this keyword plays a vital role in JavaScript. In JavaScript, this is based on how a function was called and not where it was declared (arrow functions behave the other way around).

Let's take an example to demonstrate the this keyword.

const sayGreeting = {
    name: "Parwinder",
    hello: function() {
        return `Hello, ${this.name}`;
    }
}

console.log(sayGreeting.hello()); // Hello, Parwinder

The hello method can access the name property of the object sayGreeting. When I ran the method, it is prefixed by sayGreeting. and hence it runs in the context of sayGreeting object.

Instead if I did this:

const sayGreeting = {
    name: "Parwinder",
    hello: function() {
        return `Hello, ${this.name}`;
    }
}

const hello = sayGreeting.hello;

console.log(hello === sayGreeting.hello); // true
console.log(hello()); // Hello, undefined

Even though the variable hello is equal to the method on sayGreeting, the variable is not executed in the context of sayGreeting. It is executed in the window or global context.

bind allows us to bind context. It creates a new function where the this keyword is set to what we pass to bind method.

To make the above example, I can use the bind method to bind the context of sayGreeting to hello variable.

const sayGreeting = {
    name: "Parwinder",
    hello: function() {
        return `Hello, ${this.name}`;
    }
}

const hello = sayGreeting.hello.bind(sayGreeting);
console.log(hello()); // Hello, Parwinder

Where do we need to bind in real life?

In all the above example, the data being accessed and the function trying to access it is in the same object. There are times when you want to borrow method from an object but run it in the context of another.

const sayGreeting = {
    name: "Parwinder",
    hello: function () {
        return `Hello, ${this.name}`;
    }
}

const nameObject = {
    name: "Lauren"
}

const hello = sayGreeting.hello.bind(nameObject);

console.log(hello()); // Hello, Lauren

I have the hello method in sayGreeting object. There is no need to recreate it in nameObject. I can borrow the hello method and run it in the context of nameObject.

Call

call() and apply() differs from bind(). bind() returns a new function whereas call() and apply() invoke the existing function immediately. call() takes this as the first argument and then it allows you to pass arguments one by one. These arguments would be passed to the function we called.

const sayGreeting = {
    name: "Parwinder",
    hello: function () {
        return `Hello, ${this.name}`;
    }
}

console.log(sayGreeting.hello.call(sayGreeting)); // Hello, Parwinder

With arguments:

const sayGreeting = {
    name: "Parwinder",
    hello: function (trait, color) {
        return `Hello, ${this.name}. I see you ${trait} ${color}. It is my favorite too!`;
    }
}

console.log(sayGreeting.hello.call(sayGreeting, "like", "red"));
// Hello, Parwinder. I see you like red. It is my favorite too!

Apply

apply() even though executes the function immediately like call() does but it takes an array of arguments as a second parameter instead of comma-separated values.

const sayGreeting = {
    name: "Parwinder",
    hello: function () {
        return `Hello, ${this.name}`;
    }
}

console.log(sayGreeting.hello.apply(sayGreeting)); // Hello, Parwinder

No difference between apply and call when done without arguments. But, when used with arguments.

const sayGreeting = {
    name: "Parwinder",
    hello: function (trait, color) {
        return `Hello, ${this.name}. I see you ${trait} ${color}. It is my favorite too!`;
    }
}

console.log(sayGreeting.hello.apply(sayGreeting, ["like", "red"]));
// Hello, Parwinder. I see you like red. It is my favorite too!

apply makes it easier to send n number of arguments in an array. Sending multiple arguments is easier now in ES6 by using the rest (...) operator.

Posted on by:

bhagatparwinder profile

Parwinder πŸ‘¨πŸ»β€πŸ’»

@bhagatparwinder

Happy, cheerful, confident. Web developer based out of Chicago :)

Discussion

markdown guide
 

Nice. Definitely important functions to understand. My understanding of how prototypal β€œinheritance” works is that call is used when an object calls function from further up the chain, does that sound about right?

 

I would say the method is called when you are not adjacent or you are detached from the method you are calling.

call serves an extremely important purpose of running a method under a context you provide.

This means that we can call any function, explicitly specifying the reference that this should reference in the calling function.

 

I guess what I am getting it as if you had an array called xs and you called map on that array, would you in effect be calling Array.prototype.map.call(xs,function)? Since map doesn’t belong to xs. I know I am being very specific here πŸ˜ƒ

 

I use the mnemonic Apply = Array to remember the difference

 

Bind I have used a few times. Call and Apply never. Need to find more use cases for my own projects thanks for sharing.

 

You are not alone. The need for call and apply is rarely there. Bind is used fairly often in vanilla JS or if you are working with React.