JavaScript Call Apply Bind
Control the this keyword explicitly using call, apply, and bind on any function.
TL;DR
call()andapply()invoke a function with a chosenthisvalue.apply()takes arguments as an array;call()takes a list.bind()returns a new function withthispermanently fixed.
Why this Needs Explicit Control
Call site mattersThe value of this depends on how a function is called, not where it's defined.
const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } };
const fn = user.greet;
fn(); // 'Hi, undefined' — this lost its connection to userDetached methodsPassing a method as a value, like a callback, detaches it from its original object.
Explicit controlcall, apply, and bind exist to set this explicitly regardless of call site.
Common breakageWithout explicit control, callbacks and event handlers commonly break on this.
Using call()
call(thisArg, ...args)Invoke a function immediately with arguments listed individually.
function greet(greeting) { return `${greeting}, ${this.name}`; }
greet.call({ name: 'Ada' }, 'Hi'); // 'Hi, Ada'First argument is thisThe first argument becomes this inside the function for that one call.
Positional argumentsRemaining arguments map positionally to the function's parameters.
Borrowing methodsUse call() to borrow a method from one object and run it against another.
const max = Math.max.call(null, 1, 5, 3); // 5Using apply()
apply(thisArg, argsArray)Works exactly like call(), but arguments are passed as one array.
function sum(a, b, c) { return a + b + c; }
sum.apply(null, [1, 2, 3]); // 6Array-like argumentsapply() is the better choice when arguments already exist as an array or array-like.
Math.max.apply(null, [4, 8, 2]); // 8Spread replaces itModern code often replaces apply() with the spread operator: Math.max(...nums).
Forwarding argumentsapply() still matters when forwarding an arguments object between functions.
Using bind()
bind(thisArg)Creates a new function with this permanently fixed to the given value.
const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } };
const boundGreet = user.greet.bind(user);
boundGreet(); // 'Hi, Ada' — works even detached from userDoesn't invokeUnlike call() and apply(), bind() does not invoke the function immediately.
Store for laterThe returned function can be stored, passed around, and called later safely.
Bind in constructorsBind methods in a constructor so they keep this when used as callbacks.
class Button {
constructor() { this.onClick = this.onClick.bind(this); }
onClick() { console.log(this); }
}Partial Application with bind
Prepended argumentsArguments passed to bind() after thisArg get permanently prepended to every future call.
function multiply(a, b) { return a * b; }
const double = multiply.bind(null, 2);
double(5); // 10Partial applicationThis technique is called partial application, fixing some arguments ahead of time.
Event handler contextCombine partial application with event handlers to pass extra context cleanly.
button.addEventListener('click', handleClick.bind(null, itemId));Extra arguments still workPartially applied functions still accept additional arguments at call time.
Tips
- Use bind() when passing a method as a callback or event handler, so this stays correct.
- Reach for apply() when arguments already exist as an array, such as forwarding arguments between wrapper functions.
Warnings
- Calling bind() repeatedly on the same function creates a new wrapper each time, which breaks reference equality checks like removeEventListener.
- Arrow functions ignore call, apply, and bind for this, since arrow functions always inherit this from their enclosing scope.
In Practice
call() borrows a shared formatter for different log entries, while bind() creates reusable, prefixed logger functions.
- format() reads this.level and this.message, so call() supplies a different object as this each time.
- Passing 'API' as the second call() argument fills the prefix parameter for that one invocation.
- log.bind(null, 'API') permanently fixes the prefix argument, returning a reusable specialized function.
- apiLog can still be called later with the remaining level and message arguments.
function format(prefix) {
return `[${prefix}] ${this.level}: ${this.message}`;
}
const errorEntry = { level: 'ERROR', message: 'Connection lost' };
const infoEntry = { level: 'INFO', message: 'Server started' };
console.log(format.call(errorEntry, 'API')); // '[API] ERROR: Connection lost'
console.log(format.call(infoEntry, 'API')); // '[API] INFO: Server started'
function log(prefix, level, message) {
console.log(`[${prefix}] ${level}: ${message}`);
}
const apiLog = log.bind(null, 'API');
apiLog('WARN', 'Rate limit approaching');
// '[API] WARN: Rate limit approaching'FAQ
Both invoke a function immediately with a specified this value. call() takes the function's arguments individually, separated by commas. apply() takes them bundled into a single array. They behave identically once the arguments are in place.
call() and apply() invoke the function right away. bind() does not call the function; it returns a new function with this permanently set. You call that returned function later, optionally with more arguments.
When a method is passed as a callback, like onClick={this.handleClick}, it loses its connection to the instance. Calling it later sets this to undefined or the global object instead of the instance. Binding it in the constructor, or using an arrow function class field, fixes this permanently.
Yes, this is called partial application. Any arguments passed to bind() after the this value get permanently prepended to future calls. For example, multiply.bind(null, 2) returns a function that always doubles its input.