Problem Statement
Explain call, apply, and bind methods in detail. When would you use each? Provide examples.
Explanation
Call, apply, and bind are methods for controlling the this value in function calls. They are essential for managing context in JavaScript.
Call method:
Invokes a function with specified this value and individual arguments. First parameter is this, rest are function arguments. Executes immediately. Use when you know arguments individually.
Apply method:
Invokes a function with specified this value and array of arguments. First parameter is this, second is array. Executes immediately. Use when you have arguments in an array.
Bind method:
Creates a new function with permanently bound this value. Returns new function, does not execute immediately. Can pre-set arguments for partial application. Use for event handlers, callbacks, or creating specialized functions.
Key differences:
Call and apply execute immediately, bind returns new function. Call takes comma-separated arguments, apply takes array. Bind permanently fixes this, call and apply use it for single invocation.
When to use call:
Function borrowing. Constructor chaining in inheritance. When you have individual arguments.
When to use apply:
When arguments are in an array. Using array methods on array-like objects. Math methods with array of numbers.
When to use bind:
Event handlers that need specific this. Callbacks that must maintain context. Partial application. Creating reusable specialized functions. React class component methods.
Common use cases:
Borrowing array methods for arguments or NodeList. Maintaining this in setTimeout or event handlers. Constructor chaining. Converting array-like to array. Function composition and currying.
All three methods are fundamental to JavaScript and appear frequently in interviews.
Code Solution
SolutionRead Only
// CALL METHOD
const person = {
name: 'John',
greet: function(greeting, punctuation) {
console.log(greeting + ', ' + this.name + punctuation);
}
};
const anotherPerson = { name: 'Jane' };
// Use call to invoke with different this
person.greet.call(anotherPerson, 'Hello', '!'); // 'Hello, Jane!'
// Constructor chaining
function Animal(name, type) {
this.name = name;
this.type = type;
}
function Dog(name, breed) {
Animal.call(this, name, 'Dog'); // Call parent constructor
this.breed = breed;
}
const buddy = new Dog('Buddy', 'Labrador');
console.log(buddy); // {name: 'Buddy', type: 'Dog', breed: 'Labrador'}
// APPLY METHOD
// Same as call but with array
person.greet.apply(anotherPerson, ['Hi', '...']); // 'Hi, Jane...'
// Math.max with array
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
console.log(max); // 7
// Modern alternative with spread
const max2 = Math.max(...numbers);
// Converting arguments to array
function toArray() {
return Array.prototype.slice.apply(arguments);
}
const arr = toArray(1, 2, 3, 4);
console.log(arr); // [1, 2, 3, 4]
// BIND METHOD
// Create new function with bound this
const greetJohn = person.greet.bind(person);
greetJohn('Hey', '!!!'); // 'Hey, John!!!'
// setTimeout problem and solution
const user = {
name: 'Alice',
printName: function() {
console.log(this.name);
}
};
// Problem: this is lost
setTimeout(user.printName, 1000); // undefined
// Solution: bind this
setTimeout(user.printName.bind(user), 1000); // 'Alice'
// Event handler
const button = {
label: 'Click me',
handleClick: function() {
console.log(this.label + ' was clicked');
}
};
// document.getElementById('btn')
// .addEventListener('click', button.handleClick.bind(button));
// Partial application with bind
function multiply(a, b) {
return a * b;
}
const double = multiply.bind(null, 2);
const triple = multiply.bind(null, 3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// COMPARISON EXAMPLE
function introduce(greeting, profession) {
console.log(`${greeting}, I am ${this.name}, a ${profession}`);
}
const john = { name: 'John' };
// call - execute now, individual args
introduce.call(john, 'Hello', 'Developer');
// 'Hello, I am John, a Developer'
// apply - execute now, array of args
introduce.apply(john, ['Hi', 'Engineer']);
// 'Hi, I am John, a Engineer'
// bind - return new function
const johnIntro = introduce.bind(john);
johnIntro('Hey', 'Programmer');
// 'Hey, I am John, a Programmer'
// REAL-WORLD SCENARIOS
// Scenario 1: React class component
class MyComponent {
constructor() {
this.state = { count: 0 };
// Bind methods in constructor
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
}
// Scenario 2: Array-like to Array
function convertToArray() {
return Array.prototype.slice.call(arguments);
}
// Scenario 3: Finding max in array of arrays
const data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const maxValues = data.map(arr => Math.max.apply(null, arr));
console.log(maxValues); // [3, 6, 9]
// Scenario 4: Safe hasOwnProperty
const obj = Object.create(null);
const hasProp = Object.prototype.hasOwnProperty.call(obj, 'key');
// IMPLEMENTATION EXAMPLES
// Simple call implementation
Function.prototype.myCall = function(context, ...args) {
context = context || globalThis;
const fnSymbol = Symbol();
context[fnSymbol] = this;
const result = context[fnSymbol](...args);
delete context[fnSymbol];
return result;
};
// Simple bind implementation
Function.prototype.myBind = function(context, ...boundArgs) {
const fn = this;
return function(...args) {
return fn.apply(context, [...boundArgs, ...args]);
};
};Practice Sets
This question appears in the following practice sets: