
Master JavaScript's call(), apply(), and bind() methods with analogies, examples, and use cases. Learn how to control 'this' effectively
Subhro Kr
subhbits.comIn JavaScript, the value of this depends on how a function is called.
Sometimes, you want to control what this refers to. This is where call,
apply, and bind come in. Think of them as tools to "steer" the this
keyword explicitly.

Imagine functions as cars. Normally, the driver (this) is determined by who starts the car (calls the function). But what if you want to loan your car to a friend (a different object)? call, apply, and bind let you do this:
Interactive Examples
call() invokes a function immediately, specifying this and passing arguments
individually.
Without call, apply, or bind, the this context will be either:
undefined (in strict mode) or// Define objects and function
const person1 = { name: "Alice" };
const person2 = { name: "Bob" };
function greet(greeting, punctuation) {
console.log("this value:", this);
console.log(`${greeting}, ${this.name}${punctuation}`);
}
// Call without setting 'this' context
console.log("Calling without call/apply/bind:");
greet("Hi", "!"); // Will throw error or show undefined for this.name// Define objects and a function
const person1 = { name: "Alice" };
const person2 = { name: "Bob" };
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
// Use call() to set 'this' to person1
greet.call(person1, "Hello", "!"); // Output: "Hello, Alice!"apply() works like call(), but accepts arguments as an array.
const car = { brand: "Tesla" };
function describeCar(color, year) {
console.log(`This ${color} ${this.brand} was made in ${year}.`);
}
// Using apply() with an array of arguments
describeCar.apply(car, ["red", 2023]); // Output: "This red Tesla was made in 2023."bind() returns a new function with a fixed this value. You can call it
later!
const dog = { name: "Rex" };
function bark(sound) {
console.log(`${this.name} says ${sound}!`);
}The call() method in JavaScript is used to invoke a function immediately with
a specified this value and individual arguments. Here's a detailed
explanation:
call() is to execute a function with a
specific this context. This is particularly useful when you want to borrow
a method from one object and use it on another object.call() is
func.call(thisArg, arg1, arg2, ...). Here, func is
the function you want to invoke, thisArg is the value you want to use as
this inside the function, and arg1, arg2, ... are the individual
arguments you want to pass to the function.call(), the function is executed
immediately. The this value inside the function is set to the thisArg you
provide. The remaining arguments are passed to the function as individual
parameters.Example:
const person1 = { name: "Alice" };
const person2 = { name: "Bob" };
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
// Use greet() with person1 as 'this'
greet.call(person1, "Hello", "!"); // "Hello, Alice!"
// Use greet() with person2 as 'this'
greet.call(person2, "Hey", "!!"); // "Hey, Bob!!"Analogy: You’re handing over your car keys (this) and a list of directions
(arguments) to someone else. They drive the car right away.
call, but accepts arguments as an array.func.apply(thisArg, [arg1, arg2, ...])Example:
const numbers = [5, 1, 4, 2, 3];
// Use Math.max with 'null' for 'this' (it doesn't matter here)
const max = Math.max.apply(null, numbers); // 5Why Use It?: Useful when working with functions that expect a list of
arguments, but you have an array (e.g., Math.max).
Analogy: You give a box (array) of items instead of handing them one by one.
this and
optionally preset arguments.const boundFunc = func.bind(thisArg, arg1, arg2, ...)Example:
const person = { name: "Charlie" };
function logName() {
console.log(this.name);
}
// Create a new function where 'this' is always 'person'
const boundLog = logName.bind(person);
boundLog(); // "Charlie"Partial Application: Partial application with bind allows you to create a new function with some preset arguments. This is helpful because it lets you reuse functions with specific configurations without rewriting them. For example, if you have a function that takes multiple arguments, you can use bind to fix some of those arguments, creating a simpler function that requires fewer inputs when called.
If you don't use bind, you would need to manually create a wrapper function to achieve the same effect. Here's an equivalent approach without using bind:
Without bind (Manual Partial Application)
function multiply(a, b) {
return a * b;
}
// Manually creating a partially applied function
function double(b) {
return multiply(2, b);
}
console.log(double(5)); // 10 (2 * 5)This achieves the same result as using bind, but requires manually defining a new function.
If you don't use bind, you would need to manually create a wrapper function to achieve the same effect. Here's an equivalent approach without using bind:
Without bind (Manual Partial Application)
function multiply(a, b) {
return a * b;
}
// Manually creating a partially applied function
function double(b) {
return multiply(2, b);
}
console.log(double(5)); // 10 (2 * 5)This achieves the same result as using bind, but requires manually defining a new function.
Using Closures (Partial Application)
function multiply(a, b) {
return a * b;
}
// Using a closure to create a partially applied function
function partialMultiply(a) {
return function (b) {
return multiply(a, b);
};
}
const double = partialMultiply(2);
console.log(double(5)); // Output: 10 (2 * 5)With bind (Using Partial Application)
function multiply(a, b) {
return a * b;
}
// Pre-set the first argument as 2
const double = multiply.bind(null, 2);
console.log(double(5)); // 10 (2 * 5)| Method | Description |
|---|---|
| Without bind | You manually create a new function |
| With bind | Bind pre-sets the first argument, returning a new function |
| With Closures | A function returns another function that remembers the first argument (a) |
| Method | Invokes Immediately? | Arguments Format | Returns |
|---|---|---|---|
call() | Yes | Individual (arg1, ...) | Result of the function |
apply() | Yes | Array ([args]) | Result of the function |
bind() | No | Individual (arg1, ...) | A new bound function |
Mnemonic:
Have you ever wondered about those tricky situations and unexpected surprises that can pop up when using these methods?
null/undefined as thisArg:
call/apply replace null/undefined with the
global object (e.g., window in browsers).this remains null/undefined.function test() {
console.log(this);
}
test.call(null); // In non-strict: Window; strict: nullPrimitive Values as thisArg:
5, "hello") are wrapped into their object
counterparts (Number, String).function logType() {
console.log(typeof this);
}
logType.call(5); // "object" (Number(5))Arrow Functions Ignore call/apply:
this from their lexical scope. Using
call/apply won’t override it.const obj = { x: 10 };
const arrow = () => console.log(this.x);
arrow.call(obj); // undefined (inherits global `this`)Bound this Cannot Be Overridden:
call/apply cannot change this for the bound function.const boundFunc = function () {
console.log(this.id);
}.bind({ id: 1 });
boundFunc.call({ id: 2 }); // 1 (not 2!)Partial Application with bind:
function multiply(a, b) {
return a * b;
}
const triple = multiply.bind(null, 3);
console.log(triple(4)); // 12 (3 * 4)Binding Constructors Fails:
bind on a constructor function doesn't work for binding this
because when you use new, it creates a new instance, which overrides the
bound this.function Person(name) {
this.name = name;
}
const BoundPerson = Person.bind({ name: "Alice" });
const bob = new BoundPerson("Bob"); // Bob, not Alice!Use call/apply to borrow methods from other objects:
// Borrow Array.prototype.map for array-like objects
const arrayLike = { 0: "a", 1: "b", length: 2 };
const realArray = Array.prototype.map.call(arrayLike, (item) =>
item.toUpperCase()
);
// ["A", "B"]Create specialized functions by pre-setting arguments:
// Curried logger
const log = console.log.bind(console, "[INFO]");
log("User logged in"); // [INFO] User logged inPreserve context in event handlers:
// Throttle a scroll handler
function handleScroll() {
console.log(this.id);
}
const throttled = throttle(handleScroll.bind({ id: "scroll-container" }), 100);
window.addEventListener("scroll", throttled);bind in class components to bind event
handlers.bind for reusable utility
functions.call/apply to mimic modern
methods.