What they do: All three manually control what this points to when calling functions.
The Core Problem They Solve:
javascript
let user = {
name: "John",
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
user.greet(); // "Hi, I'm John" ✓
let func = user.greet; // Extract method
func(); // "Hi, I'm undefined" ✗ - lost 'this'!Problem: When you extract a method from an object, it loses its this connection.
call() - Immediate Execution with Manual this:
Syntax: func.call(thisValue, arg1, arg2, arg3)
javascript
function greet(greeting, punctuation) {
console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}
let user = { name: "John" };
let admin = { name: "Admin" };
// Call immediately with different 'this' values
greet.call(user, "Hello", "!"); // "Hello, I'm John!"
greet.call(admin, "Hi", "."); // "Hi, I'm Admin."Mental model: “Call this function RIGHT NOW with this specific this and these arguments”
apply() - Same as call() but Arguments as Array:
Syntax: func.apply(thisValue, [arg1, arg2, arg3])
javascript
function greet(greeting, punctuation) {
console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}
let user = { name: "John" };
let args = ["Hello", "!"];
// Same result as call, but arguments in array
greet.apply(user, args); // "Hello, I'm John!"
// Useful when you have arguments in array form
let numbers = [1, 2, 3, 4, 5];
Math.max.apply(null, numbers); // 5 (find max of array)Mental model: “Apply this function RIGHT NOW with this this and this array of arguments”
bind() - Create New Function with Locked this:
Syntax: let newFunc = func.bind(thisValue, arg1, arg2)
javascript
function greet(greeting, punctuation) {
console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}
let user = { name: "John" };
// Create NEW function with locked 'this'
let boundGreet = greet.bind(user);
// Can call later - 'this' is permanently locked
boundGreet("Hello", "!"); // "Hello, I'm John!"
setTimeout(boundGreet, 1000, "Hi", "."); // Works in setTimeout!Mental model: “Create a new function that ALWAYS uses this specific this”
Quick Decision Tree:
Need to call RIGHT NOW?
- Arguments separate? → Use
call() - Arguments in array? → Use
apply()
Need to call LATER with locked this?
- Use
bind()→ Returns new function
Real-World Examples:
1. setTimeout Problem:
javascript
let user = {
name: "John",
sayHi() {
console.log(`Hi, ${this.name}`);
}
};
// Problem
setTimeout(user.sayHi, 1000); // "Hi, undefined"
// Solutions
setTimeout(user.sayHi.bind(user), 1000); // bind()
setTimeout(() => user.sayHi.call(user), 1000); // call()
setTimeout(() => user.sayHi(), 1000); // wrapper function2. Method Borrowing:
javascript
function hash() {
// 'arguments' isn't real array, borrow join method
return [].join.call(arguments, ",");
}
hash(1, 2, 3); // "1,2,3"3. Partial Application with bind:
javascript
function multiply(a, b) {
return a * b;
}
let double = multiply.bind(null, 2); // Lock first argument
double(5); // multiply(2, 5) = 10
double(8); // multiply(2, 8) = 16Interview Gotchas:
1. call vs apply memory trick:
javascript
// call = Comma separated
func.call(obj, arg1, arg2, arg3);
// apply = Array
func.apply(obj, [arg1, arg2, arg3]);2. bind doesn’t execute immediately:
javascript
let user = { name: "John" };
function greet() { console.log(this.name); }
greet.call(user); // Executes: "John"
greet.bind(user); // Returns function, doesn't execute
greet.bind(user)(); // Now executes: "John"3. bind creates permanent connection:
javascript
let user = { name: "John" };
let admin = { name: "Admin" };
function greet() { console.log(this.name); }
let boundGreet = greet.bind(user);
boundGreet.call(admin); // Still "John"! bind wins over call4. bind with arguments (partial application):
javascript
function add(a, b, c) {
return a + b + c;
}
let addFive = add.bind(null, 5); // Lock first argument
addFive(3, 2); // add(5, 3, 2) = 10The Simple Rules:
- call/apply = Execute now with custom
this - bind = Create new function with locked
this - call = arguments separate
- apply = arguments in array
- bind = can lock arguments too (partial application)
Bottom line: All three let you control this. Use call/apply for immediate execution, bind for creating functions to call later.
