These three methods control what this refers to inside a function. They're essential for understanding JavaScript's execution model.
The Problem
const user = {
name: "Rahul",
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
user.greet(); // "Hello, I'm Rahul" ✅
const greetFn = user.greet;
greetFn(); // "Hello, I'm undefined" ❌ (this lost!)call() — Invoke with explicit this
function greet(greeting, punctuation) {
console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}
const rahul = { name: "Rahul" };
const priya = { name: "Priya" };
greet.call(rahul, "Hello", "!"); // "Hello, I'm Rahul!"
greet.call(priya, "Hi", "."); // "Hi, I'm Priya."
// Arguments passed individuallyapply() — Same as call, but array arguments
greet.apply(rahul, ["Hello", "!"]); // "Hello, I'm Rahul!"
// Practical use: finding max in array
const numbers = [5, 2, 8, 1, 9];
Math.max.apply(null, numbers); // 9
// Modern alternative: spread operator
Math.max(...numbers); // 9bind() — Returns a new function with fixed this
const greetRahul = greet.bind(rahul);
greetRahul("Hey", "!"); // "Hey, I'm Rahul!"
// Partial application
const helloRahul = greet.bind(rahul, "Hello");
helloRahul("!"); // "Hello, I'm Rahul!"
// Common in React (class components)
class App extends React.Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
}Comparison
| Method | Invokes immediately? | Arguments | Returns |
|---|---|---|---|
| call | Yes | Individual | Function result |
| apply | Yes | Array | Function result |
| bind | No | Individual (partial) | New function |
Polyfill (Interview Classic)
// Implement bind from scratch
Function.prototype.myBind = function(context, ...args) {
const fn = this;
return function(...newArgs) {
return fn.apply(context, [...args, ...newArgs]);
};
};
// Implement call
Function.prototype.myCall = function(context, ...args) {
context = context || globalThis;
const sym = Symbol();
context[sym] = this;
const result = context[sym](...args);
delete context[sym];
return result;
};Arrow Functions
Arrow functions ignore call, apply, and bind. Their this is always lexical (from the enclosing scope).
const arrow = () => console.log(this);
arrow.call({ name: "Rahul" }); // Still window/global, not { name: "Rahul" }