Home > Posts > Call Bind and Apply in Javascript

Call Bind and Apply in Javascript

Mohit Ranjan
Mohit Ranjan
Cover Image for Call Bind and Apply in Javascript
Mohit Ranjan
Mohit Ranjan

Pre Requisites

this keyword

Before we dive into how to use call, apply, and bind in JavaScript, let's first understand what the this keyword means. Just like Albert Einstein said, 'Everything is relative,' the meaning or value of the this keyword also changes. But simplifying the concept, we could say, this refers to the object that is currently executing the function and provides context within the function's scope. Lets understand the different 'faces' of this keyword with examples.

console.log(this)

// window object

when we execute this, the context for console log is window object.

const obj = {
    name: 'Portgas D Ace',
    thisValue: this
}

console.log(obj.thisValue)
// window object

Again, the context in which obj was created, is window object, hence the output. Now lets try something different with object above.

const obj = {
    name: 'Portgas D Ace',
    thisValue: function () {
        let name = 'Monkey D Luffy'
        console.log(this.name)
    }
}

obj.thisValue()
// Portgas D Ace

Weird huh? Not at all! The context in which the function inside thisValue was created is object itself. So the value of this inside the function is obj, therefore this.name is equivalent to obj.name.

Let's raise the bar for the above question, think thoroughly and answer the next one.

const obj = {
    name: 'Portgas D Ace',
    thisValue: () => {
        let name = 'Monkey D Luffy'
        console.log(this.name)
    }
}

obj.thisValue()

Wait! isn't it the same as before? except its not. This time output will be undefined, because the arrow functions do not have their own this keyword, they will use the this keyword of whatever was outside the function when it was created. Outside, the value of this was window object as explained in previous example, hence the answer.

Now lets see a different example for this keyword and find move on to learn call apply and bind.

function awesome() {
  console.log(`${this.name} is Awesome!`);
}

const onePiece = {
  name: "Aokiji", 
  awesome: awesome,
  announce: function() {
    console.log(`Hey, I am ${this.name}`);
  }
};

let newAwesome = onePiece.awesome;

newAwesome();
// undefined is Awesome!

We have created newAwesome in the global context, so whatever onePiece.awesome is, the value for its this must be a window object. So when we tried to get name from this, we got undefined.

One last example, and then we will learn the Call, Bind and Apply methods. Here we go!

const onePiece = {
  country: 'Skypiea',
  timeout: function () {
    setTimeout(() => {
      console.log(this)
    }, 100)
  },
  timeout2: function () {
    setTimeout(function() {
      console.log(this)
    }, 100)
  }
}

onePiece.timeout() // onePiece
onePiece.timeout2() // window
  1. First console log will be obj2 because as we learned before, the arrow functions do not have their own this keyword, so the this inside arrow function will be of its parent's context, i.e. onePiece
  2. Second console log is window object because callbacks are executed in whole different context, which is Global (window).

Call, Apply and Bind

Call

const onePiece = {
    mc: 'Monkey D Luffy',
    sideKick: 'Zoro and Sanji',
    message: function() {
        return `${this.sideKick} will help ${this.mc} to grow stronger`
    }
}

const Naruto = {
    mc: 'Naruto Uzumaki',
    sideKick: 'Sasuke',
    message: function() {
        return `${this.sideKick} will help ${this.mc} to grow stronger`
    }
}

As we can see, the above objects has one thing common, i.e. message function. Only if we had a way to borrow the function from onePiece object. Well, we have and its called call.

const onePiece = {
    mc: 'Monkey D luffy',
    sideKick: 'Zoro and Sanji',
    message: function(goal) {
        return `${this.sideKick} will help ${this.mc} to grow stronger and get ${goal}`
    }
}

const Naruto = {
    mc: 'Naruto Uzumaki',
    sideKick: 'Sasuke',
}

const NarutoMessage = onePiece.message.call(Naruto, 'position of Hokage')

console.log(NarutoMessage) // Sasuke will help Naruto Uzumaki grow stronger and get position of Hokage`

This concept is called function borrowing. Here, call method's first argument will override the this of function. Not only this, all other arguments will act as parameter of the function we borrowed.

Apply

Its just same as call but instead of sending the extra arguments like before, it will take an array of arguments like this.

const NarutoMessage = onePiece.message.call(Naruto, ['position of Hokage'])

console.log(NarutoMessage) // Sasuke will help Naruto Uzumaki grow stronger and get position of Hokage

Bind

Bind does the same but it returns the copy of that function bound with this of our choice.

Example:

const NarutoMessage = onePiece.message.bind(Naruto, 'position of Hokage')

console.log(NarutoMessage()) // Sasuke will help Naruto Uzumaki grow stronger and get position of Hokage

Applications of Call Apply and Bind IRL

  • Since arrays don't have max method, you could use Math.max that is used for two numbers like this :

    arr = [3, 6, 77, 69, 22, 0]
    
    // No need to assign/override **this**, so null.
    console.log(Math.max.apply(null, arr)) //77
    
  • You can use the concept of bind and apply to create a function that curries a given function.

  • You can use bind to bind an event listener to an element :

    const button = document.getElementById("myButton");
    
    const handleClick = function(event) {
      console.log("Button clicked!", this); // 'this' is the button element
    };
    
    button.addEventListener("click", handleClick.bind(button));