JavaScript Call Apply Bind
Control the this keyword explicitly using call, apply, and bind on any function.
TL;DR
- 01
call()andapply()invoke a function with a chosenthisvalue. - 02
apply()takes arguments as an array;call()takes a list. - 03
bind()returns a new function withthispermanently fixed.
Tips
- 01Use bind() when passing a method as a callback or event handler, so this stays correct.
- 02Reach for apply() when arguments already exist as an array, such as forwarding arguments between wrapper functions.
Warnings
- 01Calling bind() repeatedly on the same function creates a new wrapper each time, which breaks reference equality checks like removeEventListener.
- 02Arrow functions ignore call, apply, and bind for this, since arrow functions always inherit this from their enclosing scope.
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.
Function.prototypeAll three live on Function.prototype, so every function has access to them.
Common breakageWithout explicit control, callbacks and event handlers commonly break on this.
Legacy codeUnderstanding these three methods is essential for working with older, non-arrow-function code.
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); // 5null or undefinedPassing null or undefined as thisArg uses the global object in non-strict mode.
Single invocation onlycall() does not change the original function; it only affects that single invocation.
Using 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.
Synchronous returnBoth call() and apply() execute the function synchronously and return its result.
Choosing between themChoosing between call and apply is purely about argument shape — list versus array.
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); }
}Fixed permanentlyCalling bind() again on an already-bound function cannot change its fixed this.
Bound function namesBound functions report 'bound functionName' when inspected, which helps when debugging.
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.
Specialized utilitiesUse partial application to build specialized utility functions from general ones.
Avoids wrappersThis pattern avoids writing repetitive wrapper functions for common argument combinations.
In Practice
call() borrows a shared formatter for different log entries, while bind() creates reusable, prefixed logger functions.
- 01format() reads this.level and this.message, so call() supplies a different object as this each time.
- 02Passing 'API' as the second call() argument fills the prefix parameter for that one invocation.
- 03log.bind(null, 'API') permanently fixes the prefix argument, returning a reusable specialized function.
- 04apiLog 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.
Calling bind() on an arrow function has no effect on this, because arrow functions never have their own this. You can still bind arguments for partial application, but the this value stays whatever it was lexically. Use a regular function if you need bind() to control this.