JavaScript Notes
Master JavaScript call vs apply vs bind with side-by-side comparisons, decision rules, real examples, this binding diagrams, and top interview Q&A.
The Big Picture
All three methods — call(), apply(), and bind() — live on Function.prototype and serve the same fundamental purpose: controlling what this means inside a function. Their difference lies in *when* the function runs and *how* you pass arguments.
If you can answer "Do I run it now or later? Do I have separate args or an array?" — you've picked the right method.
Quick Decision Rule
Need to run NOW with individual arguments? → call()
Need to run NOW with an array of arguments? → apply()
Need to save for LATER (callbacks/events)? → bind()Side-by-Side Syntax
Hello, Riya! Hello, Riya! Hello, Riya!
All three produce the same output here — the difference is in timing and argument format.
Complete Comparison Table
| Feature | call() | apply() | bind() |
|---|---|---|---|
| Executes immediately | ✅ Yes | ✅ Yes | ❌ No |
| Returns | Function result | Function result | New bound function |
| Argument format | (thisArg, a, b, c) | (thisArg, [a, b, c]) | (thisArg, a, b) → preset |
Changes this permanently | ❌ No | ❌ No | ✅ Yes (in new fn) |
| Works on arrow functions | ❌ No | ❌ No | ❌ No |
| Partial application | ❌ No | ❌ No | ✅ Yes |
| Re-bindable | N/A | N/A | ❌ No |
Called with new | N/A | N/A | this overridden by new |
| Legacy array-spreading | ❌ | ✅ apply(null, arr) | ❌ |
| Modern alternative | — | ...spread | Arrow class fields |
Step-by-Step Execution Trace
Using call()
function intro(city, role) {
return `${this.name} — ${city} — ${role}`;
}
const user = { name: "Aman" };
intro.call(user, "Delhi", "Engineer");Aman — Delhi — Engineer
Using apply()
Aman — Delhi — Engineer
Using bind()
const boundIntro = intro.bind(user, "Delhi");
const result = boundIntro("Engineer");
console.log(result);Aman — Delhi — Engineer
Execution Context Diagram
Unique Use Cases
When to use call() 📞
// 1. Type checking with Object.prototype.toString
function getType(value) {
return Object.prototype.toString.call(value);
}
console.log(getType([]));
console.log(getType({}));
console.log(getType(null));[object Array] [object Object] [object Null]
// 2. Constructor chaining
function Animal(name) {
this.name = name;
}
function Dog(name, breed) {
Animal.call(this, name); // Inherit Animal's setup
this.breed = breed;
}
const dog = new Dog("Rex", "Lab");
console.log(dog.name, dog.breed);Rex Lab
When to use apply() 📦
9
// 2. Arguments object conversion
function logAll() {
const args = Array.prototype.slice.apply(arguments);
console.log(args.join(", "));
}
logAll("a", "b", "c");a, b, c
When to use bind() 🔗
10
Common Mistakes — All Three
❌ Mistake 1 — Using call() with an Array (should be apply)
NaN
// CORRECT options:
sum.apply(null, nums);
sum.call(null, ...nums);6
❌ Mistake 2 — Expecting bind() to Execute
function say() { return `Hello, ${this.name}`; }
const user = { name: "Bob" };
// WRONG — stores function reference, doesn't run it
const result = say.bind(user);
console.log(result); // Prints function, not "Hello, Bob"[Function: bound say]
// CORRECT
const result = say.bind(user)();
console.log(result);Hello, Bob
❌ Mistake 3 — Using any of the three on Arrow Functions for this
this.name = undefined this.name = undefined this.name = undefined
Arrow functions always capture this from where they were defined. No method can change it.
Full Practical Example — All Three Together
Student: Sneha | Score: 95 | Math: A+ Student: Sneha | Score: 95 | Science: A Student: Sneha | Score: 95 | English: A
Interview Questions 🎯
Q1. What is the main difference between call(), apply(), and bind()?
| Executes? | Args format | Returns | |
|---|---|---|---|
| - | ----------- | ------------- | --------- |
call() | Immediately | Individual | Result |
apply() | Immediately | Array | Result |
bind() | Later (returns fn) | Individual + preset | New function |
Q2. When would you use apply() over call()?
Use apply() when your arguments are already stored in an array or array-like object (e.g., arguments, result of a split). call() is for when arguments are individual values. In modern code, call(thisArg, ...array) with spread can replace most apply() calls.
Q3. Can you re-bind a function that's already been bound with bind()?
No. Once a bound function is created, its this is permanent. Any subsequent call(), apply(), or bind() calls on the bound function cannot change this. Only the preset arguments from the first bind can be extended with new args.
Q4. What does bind() return vs call()/apply()?
call()andapply()return the result of the called functionbind()returns a new bound function (a wrapper)
Q5. Does it make sense to use call/apply/bind on arrow functions?
Not for this binding — arrow functions ignore the thisArg parameter entirely. You can still *call* arrow functions via call()/apply(), but this will remain what it was at definition time.
Q6. Which method is safest in modern code?
call()andapply()are equivalent power — choose based on argument format- Modern code often replaces
apply()with spread:fn.call(ctx, ...args) bind()is preferred for callbacks (event handlers, setTimeout, React)- Arrow functions replace
bind()in many modern patterns
Q7. What is partial application and how does bind() enable it?
Partial application means creating a function with some arguments pre-filled:
function add(a, b) { return a + b; }
const add5 = add.bind(null, 5); // a = 5 is pre-filled
console.log(add5(3)); // b = 3 → 5 + 3 = 88
Q8. How does call() enable constructor inheritance?
function Vehicle(type) { this.type = type; }
function Car(type, brand) {
Vehicle.call(this, type); // Inherit Vehicle's properties
this.brand = brand;
}
const c = new Car("Sedan", "Honda");
console.log(c.type, c.brand);Sedan Honda
Key Takeaways 🔑
- All three methods control
this— the difference is when and how call()→ now, args separate → returns resultapply()→ now, args as array → returns resultbind()→ later, args preset → returns new function- None work on arrow functions for
this— lexicalthisalways wins bind()is irreversible — you cannot rebind a bound function- Modern spread syntax (
...) covers mostapply()use cases - Arrow functions + class fields often replace
bind()in modern code
Summary
call(), apply(), and bind() are three Function.prototype methods that all control the this value inside a function. The decision is straightforward: use call() when you want to run a function immediately with individual arguments; use apply() when you want to run it immediately with arguments in an array; use bind() when you need a new reusable function with this locked in for later. None of these methods work on arrow functions for this binding. In modern JavaScript, spread syntax reduces the need for apply(), and arrow class fields reduce the need for bind() — but understanding all three is essential for deep JavaScript knowledge and interviews.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript call() vs apply() vs bind() - Complete Comparison Guide.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, advanced, call, apply
Related JavaScript Master Course Topics