learn Javscript features — call, apply and bind with practical and theoratical questions with explanation

Level Up Your JavaScript Skills: Mastering call(), apply(), and bind() for Better Code

Meenu Matharu
6 min readSep 19, 2023

Have you ever encountered a situation in JavaScript where this seemed to have a mind of its own, causing unexpected behavior in your code? If you've been perplexed by the nuances of this in JavaScript, you're not alone. Understanding this is a crucial skill for any JavaScript developer, and it can make or break your code's functionality. In this story, we'll unravel the mysteries of this in JavaScript and explore how the apply(), bind(), and call() methods come to the rescue to resolve this conundrum."

The following JavaScript code demonstrates the usage of this keyword within functions.

var fullname = 'Vik Doe';  // Global variable declaration
var obj = { // Object declaration
fullname: 'Jonas David',
prop: {
fullname: 'Arabita Rosa',
getFullname: function() {
return this.fullname; // A method that returns the 'fullname' property of 'prop'
}
}
};

console.log(obj.prop.getFullname()); // Outputs 'Arabita Rosa'
var test = obj.prop.getFullname; // Assigning the 'getFullname' method to the 'test' variable
console.log(test()); // Outputs 'Vik Doe'

Lets get into the execution of this code

  1. A global variable fullname is declared and set to 'Vik Doe'.
  2. An object obj is defined with several properties. Inside obj, there's another object prop containing a method getFullname. This method returns the fullname property of the prop object.
  3. The first console.log(obj.prop.getFullname()) line calls the getFullname method of the prop object, and since it's called as a method of an object, this inside the method refers to prop. Therefore, it returns 'Arabita Rosa', which is logged to the console.
  4. The getFullname method is assigned to the test variable without the parentheses. When test() is called in the second console.log(test()) line, it's no longer in the context of the prop object. Instead, it's executed in the global context (or undefined if in strict mode). As a result, this inside the function refers to the global object, and since there's no global fullname variable defined, it returns 'Vik Doe', which is logged to the console.

Key Takeaway for Beginners:

This example illustrates the importance of understanding how the this keyword behaves in different contexts in JavaScript. When a method is called as part of an object (as in the first console.log), this points to that object. However, when the method is assigned to a variable and called independently (as in the second console.log), this may not refer to the same object, leading to potentially unexpected results. This behaviour is a common source of bugs and is important to grasp as a beginner in JavaScript.

call(), bind() and apply()

Here’s the code using apply(), call(), and bind() to correctly set the context and ensure that the last console.log() prints 'Arabita Rosa':

var fullname = 'Vik Doe';  // Global variable declaration
var obj = { // Object declaration
fullname: 'Jonas David',
prop: {
fullname: 'Arabita Rosa',
getFullname: function() {
return this.fullname; // A method that returns the 'fullname' property of 'prop'
}
}
};

console.log(obj.prop.getFullname()); // Outputs 'Arabita Rosa'

var test = obj.prop.getFullname; // Assigning the 'getFullname' method to the 'test' variable

// Using apply() to set the context to 'obj.prop'
console.log(test.apply(obj.prop)); // Outputs 'Arabita Rosa'

// Using call() to set the context to 'obj.prop'
console.log(test.call(obj.prop)); // Outputs 'Arabita Rosa'

// Using bind() to create a new function with the context set to 'obj.prop'
var boundTest = test.bind(obj.prop);
console.log(boundTest()); // Outputs 'Arabita Rosa'In this modified code, we use call(obj.prop) when invoking the test function, which explicitly sets the context of the function to obj.prop. As a result, this inside the function refers to obj.prop, and it returns 'Aurelio De Rosa', which is logged to the console.

In this code, we demonstrate three different ways to set the context:

  1. apply(): The apply() method allows you to pass an object as the context for the function. When we use apply(obj.prop), it sets the this context inside the test function to obj.prop, and it correctly outputs 'Arabita Rosa'.
  2. call(): Similar to apply(), the call() method sets the context to the provided object. When we use call(obj.prop), it also sets the this context to obj.prop and produces the correct output.
  3. bind(): The bind() method creates a new function with the specified context. In this case, we create boundTest, which is a new function with this set to obj.prop. When we call boundTest(), it correctly logs 'Arabita Rosa'.

Lets dive into some more JavaScript code snippets based on call(), apply(), and bind() for understanding the concept and for practice. Following are the various scenarios to showcase the versatility of these methods:

Example 1: Using call() and apply()

function greet(greeting) {
console.log(greeting + ' ' + this.name);
}

var person = {
name: 'Alice',
};

// Using call() to invoke the function with a specific context and arguments
greet.call(person, 'Hello'); // Outputs 'Hello Alice'

// Using apply() to invoke the function with a specific context and an array of arguments
greet.apply(person, ['Hi']); // Outputs 'Hi Alice'

Example 2: Using bind() to Create a New Function

function multiply(x, y) {
return x * y;
}

// Using bind() to create a new function with preset arguments
var double = multiply.bind(null, 2);

console.log(double(5)); // Outputs 10

Example 3: Dynamic Context with call()

function printInfo() {
console.log('Name:', this.name, ', Age:', this.age);
}

var user1 = { name: 'John', age: 30 };
var user2 = { name: 'Jane', age: 25 };

// Using call() to invoke printInfo with different contexts
printInfo.call(user1); // Outputs 'Name: John , Age: 30'
printInfo.call(user2); // Outputs 'Name: Jane , Age: 25'

Example 4: Borrowing Methods with call()

var person = {
name: 'Alice',
greet: function () {
return 'Hello, ' + this.name;
},
};

var anotherPerson = {
name: 'Bob',
};

// Using call() to borrow the greet method from person
var greeting = person.greet.call(anotherPerson);
console.log(greeting); // Outputs 'Hello, Bob'

Here are some theoretical questions about call(), bind(), and apply() that can be used in interview process to assess a candidate's knowledge of these JavaScript methods:

Question: Explain call(), apply(), and bind() in JavaScript. What are their primary purposes?

Answer: call(), apply(), and bind() are methods available to functions in JavaScript.

  • call() and apply() are used to invoke functions with a specific context (the this value) and a set of arguments. call() accepts arguments individually, while apply() accepts arguments as an array.
  • bind() is used to create a new function with a permanently bound context. It returns a new function that, when called, will always execute with the provided context.

Question: How does the call() method differ from the apply() method? Provide examples of when each would be more appropriate to use.

Answer: call() and apply() are similar in that they both invoke a function with a specific context. However, they differ in how they accept arguments.

  • call() accepts arguments individually, while apply() accepts an array of arguments.
  • Use call() when you know the number and values of the arguments, and you can pass them individually. Use apply() when you have an array of arguments or want to pass a dynamic number of arguments.
function sum(a, b) {
return a + b;
}

var args = [5, 3];

sum.call(null, 5, 3); // Using call()
sum.apply(null, args); // Using apply()

Question: Explain the concept of function currying. How can bind() be used to implement currying in JavaScript?

Answer: Function currying is a technique in functional programming where a function with multiple arguments is transformed into a series of unary (single-argument) functions.

  • bind() can be used to implement currying by partially applying arguments and returning a new function that expects the remaining arguments.
function multiply(x, y) {
return x * y;
}

var double = multiply.bind(null, 2);
var triple = multiply.bind(null, 3);

double(5); // Outputs 10
triple(5); // Outputs 15

Question: Can you explain how bind() works under the hood? What does it return, and how does it affect the original function?

Answer: bind() creates a new function with the specified context (the this value) permanently bound.

  • It returns a new function that wraps the original function and sets the context to the provided value.
  • When you invoke the new function created by bind(), it will execute with the bound context, and any subsequent calls to it will maintain the same context.

Question: What are some potential use cases for call(), apply(), and bind() in real-world JavaScript development?

Answer: call() and apply() are often used for method borrowing, dynamic context switching, and function composition.

  • bind() is commonly used to create functions with preset arguments, create event handlers with a specific context, or ensure that a callback function retains a particular this context.

I hope these questions will help you to grasp the understanding of how this context in JavaScript is essential for avoiding unexpected behaviour in your code and how call(), apply(), and bind() are the valuable tools for developers to manage this context effectively.

--

--

Meenu Matharu
Meenu Matharu

Written by Meenu Matharu

🚀 Passionate Frontend Developer | Storyteller on a Coding Journey 🌟 Dive deep into the world of frontend technologies like HTML, CSS, JavaScript and React

No responses yet