Advanced JavaScript: Call, Bind, Apply — A Deep Dive That’ll Make You Say "Whoa!"


Hey there! Buckle up because we’re about to take a wild ride through some of the coolest, trickiest, and downright magical methods in JavaScript: call
, bind
, and apply
. These bad boys are like the secret sauce to mastering function invocation and the infamous this
keyword. By the end of this article, you’ll be slinging these methods around like a JS ninja—and trust me, your code’s gonna thank you.
Let’s dive in with zero fluff and maximum fun. Ready? Let’s roll!
What’s the Deal with this
Anyway?
Before we get into the juicy stuff, let’s talk about this
. In JavaScript, this
is like that one friend who changes their vibe depending on who they’re hanging out with. It’s all about context. Sometimes this
points to the window, sometimes an object, and sometimes it’s just lost in the void (looking at you, arrow functions).😒
Here’s a quick example to set the stage:
const person = {
name: "Suman",
greet() {
console.log(`Hi, I’m ${this.name}!`);
},
};
person.greet(); // Hi, I’m Suman!
Cool, right? this
knows it’s inside person
. But what if we move greet
out of there?
const lonelyGreet = person.greet;
lonelyGreet(); // Hi, I’m undefined!
Ooh no! this
lost its context and defaulted to the global scope. That’s where call
, bind
, and apply
swoop in like superheroes to save the day. Let’s meet them!
Meet the Crew: Call, Apply, and Bind
These three methods are all about controlling this
and passing arguments to functions. They live on every function’s prototype (yep, Function.prototype
), so every function you write has access to them. Let’s break them down with some real talk and code.
1. call
— The Context-Switching Wizard
Imagine call
as a megaphone that yells, “Hey function, run RIGHT NOW, and use THIS as your this
!” It invokes the function immediately and lets you set the context explicitly.
Here’s the syntax:
function.call(thisArg, arg1, arg2, ...);
Let’s see it in action:
const dog = {
name: "Kallu",
};
const cat = {
name: "Kaliya",
};
function sayHello(greeting, punctuation) {
console.log(`${greeting}, I’m ${this.name}${punctuation}`);
}
sayHello.call(dog, "Woof", "!"); // Woof, I’m Kallu!
sayHello.call(cat, "Meow", "?"); // Meow, I’m Kaliya?
Whoa, did you see that? We borrowed sayHello
and told it to use dog
as this
, then cat
. The arguments "Woof"
and "!"
got passed in right after the thisArg
. It’s like giving this
a VIP pass to any object we want.
Real-World Use Case: Ever needed to borrow a method from one object for another? Check this out:
const chef = {
name: "Gordon",
cook() {
console.log(`${this.name} is cooking up a storm!`);
},
};
const newbie = { name: "Bob" };
chef.cook.call(newbie); // Bob is cooking up a storm!
call
just made Bob a chef for a day. Pretty slick, huh?
2. apply
— The Array-Loving Twin of call
apply
is like call
’s quirky sibling. It does the same thing—invokes a function and sets this
—but it takes arguments as an array. Think of it as the method that says, “Here’s a neatly packed lunchbox of args, enjoy!”
Syntax:
function.apply(thisArg, [arg1, arg2, ...]);
Let’s tweak our earlier example:
function sayHello(greeting, punctuation) {
console.log(`${greeting}, I’m ${this.name}${punctuation}`);
}
sayHello.apply(dog, ["Woof", "!"]); // Woof, I’m Kallu!
sayHello.apply(cat, ["Meow", "?"]); // Meow, I’m Kaliya?
Same result as call
, but we passed the args in an array. Why’s this cool? Imagine you’ve got an array lying around:
const args = ["Bark", "!!"];
sayHello.apply(dog, args); // Bark, I’m Kallu!!
Real-World Use Case: Math nerds, this one’s for you. Ever wanted to find the max value in an array? Math.max doesn’t take arrays directly, but apply saves the day:
const numbers = [5, 12, 3, 99, 42];
const max = Math.max.apply(null, numbers); // 99
apply
unpacks that array like a pro. (Side note: Nowadays, the spread operator [...numbers]
does this cleanly too, but apply
still feels OG.)
3. bind
— The Time-Traveling Clone Maker
Now, bind
is the chill one in the group. It doesn’t invoke the function right away—it hands you back a new function with this
locked in place. It’s like saying, “Hey, take this function, set its this
, and call it whenever you’re ready.”
Syntax:
const newFn = function.bind(thisArg, arg1, arg2, ...);
Check this out:
function sayHello(greeting, punctuation) {
console.log(`${greeting}, I’m ${this.name}${punctuation}`);
}
const dogHello = sayHello.bind(dog, "Woof", "!");
dogHello(); // Woof, I’m Kallu!
const catHello = sayHello.bind(cat, "Meow", "?");
catHello(); // Meow, I’m Kaliya?
BOOM! dogHello
and catHello
are now standalone functions with their this
permanently tied to dog
and cat
. You can call them anytime, anywhere.
Real-World Use Case: Event listeners love bind. Imagine a button that logs a counter:
const counter = {
count: 0,
increment() {
this.count++;
console.log(this.count);
},
};
document.querySelector("button").addEventListener("click", counter.increment); // NaN, NaN, NaN...
Oh no! this points to the button, not counter. Let’s fix it with bind:
document.querySelector("button").addEventListener("click", counter.increment.bind(counter));
// 1, 2, 3...
Now this
stays loyal to counter
. Crisis averted!
Call vs. Apply vs. Bind: The Showdown
Still confused about when to use which? Here’s a quick cheat sheet:
call
: Run it now, pass args one by one. Great for quick context switches.apply
: Run it now, pass args as an array. Perfect for array unpacking.bind
: Don’t run it yet—just lock inthis
and maybe some args. Ideal for callbacks or reusable functions.
Let’s see them all in one epic example:
const hero = { name: "Spider-Man" };
function swing(action, style) {
console.log(`${this.name} swings ${action} with ${style}!`);
}
// Call
swing.call(hero, "fast", "web-tastic"); // Spider-Man swings fast with web-tastic!
// Apply
const moves = ["slow", "flair"];
swing.apply(hero, moves); // Spider-Man swings slow with flair!
// Bind
const swingLater = swing.bind(hero, "high", "confidence");
swingLater(); // Spider-Man swings high with confidence!
So there you have it—call
, apply
, and bind
demystified with heaps of code. These methods aren’t just fancy tricks; they’re tools that’ll level up your JavaScript game. Whether you’re borrowing methods, wrangling this
, or prepping callbacks, you’ve got the power now.
In the next one we will dive into Debouncing and Throttling in JavaScript.
Until next time! 🙌
Subscribe to my newsletter
Read articles from Suman Sarkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
