Technology · JavaScript
AdvancedJavaScript Call Apply Bind
Control the this keyword explicitly using call, apply, and bind on any function.
TL;DR
- 01Call and apply invoke a function with a chosen this value.
- 02Apply takes arguments as an array; call takes a list.
- 03Bind returns a new function with this permanently fixed.
Why this Needs Explicit Control
- The value of
thisdepends 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 user - Passing a method as a value, like a callback, detaches it from its original object.
call,apply, andbindexist to setthisexplicitly regardless of call site.- All three live on
Function.prototype, so every function has access to them. - Without explicit control, callbacks and event handlers commonly break on
this. - Understanding these three methods is essential for working with older, non-arrow-function code.
Using call()
- Use
.call(thisArg, arg1, arg2, ...)to invoke a function immediately with arguments listed individually.function greet(greeting) { return `${greeting}, ${this.name}`; } greet.call({ name: 'Ada' }, 'Hi'); // 'Hi, Ada' - The first argument becomes
thisinside the function for that one call. - Remaining arguments map positionally to the function's parameters.
- Use
call()to borrow a method from one object and run it against another.const max = Math.max.call(null, 1, 5, 3); // 5 - Passing
nullorundefinedasthisArguses the global object in non-strict mode. call()does not change the original function; it only affects that single invocation.
Using apply()
- Use
.apply(thisArg, argsArray)exactly likecall(), but pass arguments as one array.function sum(a, b, c) { return a + b + c; } sum.apply(null, [1, 2, 3]); // 6 apply()is the better choice when arguments already exist as an array or array-like.Math.max.apply(null, [4, 8, 2]); // 8- Modern code often replaces
apply()with the spread operator:Math.max(...nums). apply()still matters when forwarding anargumentsobject between functions.- Both
call()andapply()execute the function synchronously and return its result. - Choosing between them is purely about argument shape — list versus array.
Using bind()
- Use
.bind(thisArg)to create a new function withthispermanently fixed.const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } }; const boundGreet = user.greet.bind(user); boundGreet(); // 'Hi, Ada' — works even detached from user - Unlike
call()andapply(),bind()does not invoke the function immediately. - The returned function can be stored, passed around, and called later safely.
- Bind methods in a constructor so they keep
thiswhen used as callbacks.class Button { constructor() { this.onClick = this.onClick.bind(this); } onClick() { console.log(this); } } - Calling
bind()again on an already-bound function cannot change its fixedthis. - Bound functions report
'bound functionName'when inspected, which helps when debugging stacks.
Partial Application with bind
- Arguments passed to
bind()afterthisArgget permanently prepended to every future call.function multiply(a, b) { return a * b; } const double = multiply.bind(null, 2); double(5); // 10 - This technique is called partial application, fixing some arguments ahead of time.
- Combine partial application with event handlers to pass extra context cleanly.
button.addEventListener('click', handleClick.bind(null, itemId)); - Partially applied functions still accept additional arguments at call time.
- Use partial application to build specialized utility functions from general ones.
- This pattern avoids writing repetitive wrapper functions for common argument combinations.
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.
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.