JS Function Scope Manipulation

apply, call and bind methods

apply, call and bind are methods that can be called on any JS function and are used to call that function in a specified scope. this inside the function will refer to the specified scope. The specified scope can be different from the scope in which the function was defined.

apply and call methods

apply and call have just a slight difference in their signature. Both take in scope as the first argument. apply takes an Array of function arguments as the second argument. call takes these arguments sequentially second argument onwards. Both apply and call execute the function immediately.

Let’s try to understand apply and call methods using code snippets.

Snippet 1

const cat = {
  name: 'cat',
  greet: function() {
    console.log(`Hello, I am a ${this.name}.`);
  }
}

const dog = {
  name: 'dog'
}

cat.greet(); // Prints - Hello, I am a cat.
cat.greet.call(dog); // Prints - Hello, I am a dog.
cat.greet.apply(dog); // Prints - Hello, I am a dog.


In the above snippet, we can see that both apply and call behave the same way. Also since greet does not have any arguments, both apply and call usages look the same. In the next snippet, let's see example with arguments.

Snippet 2

const cat = {
  name: 'cat',
  greet: function() {
    console.log(`Hello, I am a ${this.name}. Second argument: ${arguments[1]}`);
  }
}

const dog = {
  name: 'dog'
}

cat.greet.call(dog, 1, 2); // Prints - Hello, I am a dog. Second argument: 2
cat.greet.apply(dog, [1, 2]); // Prints - Hello, I am a dog. Second argument: 2

In the above snippet, we can see the only difference apply and call usages. apply takes in an Array of arguments that are passed to the function while calling. call takes these arguments one by one.

bind method

bind method returns a new function. This new function, when called, makes the call to the original function in the specified scope. Arguments can be passed at 2 places - one at the time of binding, and the second at the time of the new function call. Check out the 'snippet 4' below to get to know what happens with these arguments.

Snippet 3

const cat = {
  name: 'cat',
  greet: function() {
    console.log(`Hello, I am a ${this.name}. Second argument: ${arguments[1]}`);
  }
}

const dog = {
  name: 'dog'
}

const newFunction = cat.greet.bind(dog); // greet is not called yet.
newFunction(1, 2); // Prints - Hello, I am a dog. Second argument: 2

In the above snippet, we can see that the bind method does not call the greet function. It returns a newFunction, which can be called later.

Snippet 4

const cat = {
  name: 'cat',
  greet: function() {
    console.log(`Hello, I am a ${this.name}. All argument: ${Array.from(arguments)}`);
  }
}

const dog = {
  name: 'dog'
}

const newFunction = cat.greet.bind(dog, 1, 2); // greet is not called yet.
newFunction(3, 4); // Prints - Hello, I am a dog. All argument: 1,2,3,4

In the above snippet, 2 arguments (say a1) are passed at the time of bind. Another 2 arguments (say a2) are passed at the time of the call to the new function. From the data which is printed, we can see that a1 and a2 are all passed to the greet function, and a1 precede a2.

Kedar Chandrayan

Kedar Chandrayan

I focus on understanding the WHY of each requirement. Once this is clear, then HOW becomes easy. In my blogs too, I try to take the same approach.