skip to content

call, apply and bind

Setting this yourself, plus the detail that bind returns a new permanently bound function you cannot rebind. Common follow-ups are partial application with bind and what happens when you call new on a bound function.

part ofJavaScriptoverview, primer and where to startread it →
on this pageshow

questions

6

In JavaScript, what is the difference between Function.prototype.call and Function.prototype.apply, and how does Function.prototype.bind differ from both?

level: juniorimportance: must knowfreq 80%

answer

  1. all three set this explicitly
  2. one of them does not invoke
  3. comma versus array
  4. returns a function, not a result

basics

~20 s

call and apply both invoke the function immediately with an explicit this; call takes the arguments individually, apply takes them as one array-like. bind invokes nothing — it returns a new function whose this is permanently fixed.

solid answer

~40 s

All three live on `Function.prototype` and all three let you choose the `this` value explicitly instead of relying on how the function is called. `call` and `apply` are identical except in how they take the arguments: `fn.call(thisArg, a, b)` spreads them out, `fn.apply(thisArg, [a, b])` takes a single array or array-like. Both invoke the function right there and return its result. `bind` is the odd one out — it does not invoke anything. `fn.bind(thisArg, a)` returns a brand-new function that, whenever it is later called, runs `fn` with `this` set to `thisArg` and with `a` already supplied as the first argument. A useful mnemonic is call = comma, apply = array, bind = build a function for later.

code

javascript · 12 lines
javascript
function greet(greeting, punctuation) {
  return greeting + ', ' + this.name + punctuation;
}

const user = { name: 'Ada' };

console.log(greet.call(user, 'Hi', '!'));     // 'Hi, Ada!'
console.log(greet.apply(user, ['Hi', '!'])); // 'Hi, Ada!'

const greetAda = greet.bind(user, 'Hi');
console.log(typeof greetAda);                 // 'function' - nothing ran yet
console.log(greetAda('!'));                   // 'Hi, Ada!'

go deeper

for a junior

Be able to state the signatures cold: call takes the receiver then comma-separated arguments, apply takes the receiver then one array, bind returns a new function instead of running anything.

for a middle

Explain what the returned bound function actually remembers, and how a strict-mode function treats a null or primitive thisArg differently from a sloppy-mode one.

for a senior

Show judgment about when explicit receiver control is the right tool at all, and flag the argument-count limit that makes apply or spread unsafe for very large arrays.

for a principal

Frame it as an API-design question: a library that accepts callbacks should decide deliberately whether it offers a thisArg parameter or expects callers to bind, and document that contract.

## The problem all three solve In JavaScript a function's `this` is not decided when the function is written — it is decided when the function is *called*. `obj.method()` gives `this === obj`, but pulling the same function out and calling it plainly gives something else entirely. `call`, `apply` and `bind` are the language's escape hatch: they let the *caller* state the receiver explicitly rather than letting the call syntax decide it. All three are methods on `Function.prototype`, so every function object inherits them. ## call and apply: same job, different argument shape ```js function greet(greeting, punctuation) { return greeting + ', ' + this.name + punctuation; } const user = { name: 'Ada' }; greet.call(user, 'Hi', '!'); // 'Hi, Ada!' — arguments listed out greet.apply(user, ['Hi', '!']); // 'Hi, Ada!' — arguments in one array ``` The first parameter of each is the `this` value; everything after it is the argument list. `call` takes them as ordinary comma-separated arguments; `apply` takes exactly one further value, an array or array-like object, and spreads it into the parameters. Semantically there is no other difference: both call the function synchronously and return whatever it returns. `apply` earns its keep when the arguments are already sitting in an array and you do not know how many there are: ```js const nums = [3, 1, 4, 1, 5]; Math.max.apply(null, nums); // 5 — Math.max takes separate arguments ``` Since ES2015 the spread syntax `Math.max(...nums)` does the same thing more readably, so new code rarely needs `apply` for this. It still appears when forwarding a whole argument list inside a generic wrapper. ## What happens to the thisArg The treatment of the first argument depends on whether the *called* function is strict: - In strict mode (which includes all module code and class bodies), the value is passed through untouched: `fn.call(null)` really does give `this === null`, and `fn.call(7)` gives the primitive number `7`. - In sloppy mode, `null` and `undefined` are replaced by `globalThis`, and primitives are boxed into wrapper objects, so `this` inside is a `Number` object rather than `7`. This is why `Math.max.apply(null, nums)` is harmless — `Math.max` ignores its receiver entirely — but passing `null` to a function that actually reads `this.something` will throw in strict mode. ## bind: build now, call later ```js const greetAda = greet.bind(user, 'Hi'); greetAda('!'); // 'Hi, Ada!' greetAda('?'); // 'Hi, Ada?' ``` `bind` returns a *new function object*. The original is untouched — `bind` never mutates anything. The returned function remembers two things: the `this` value you supplied, and any arguments you supplied after it, which are prepended to whatever arguments the caller passes later. Nothing runs until you invoke the result. That one difference — returns a function versus invokes immediately — is the whole reason all three exist. When you need to *hand a function to somebody else* (a callback, a stored handler, a value in a table) and still control its receiver, you need `bind`, because `call` and `apply` would have already run it. ## Choosing between them - You have the arguments written out and want to run it now → `call`. - You have the arguments in an array and want to run it now → `apply` (or spread with `call`). - You want a reusable function value with the receiver already decided → `bind`. A common mistake is `element.onclick = handler.call(obj)`, which assigns the *result* of calling `handler` immediately — usually `undefined` — rather than a function. `bind` is what that line wanted. ## Details worth knowing `call` and `apply` return the function's return value, so `Object.prototype.hasOwnProperty.call(obj, 'k')` is a safe way to invoke a method that a particular object might have shadowed or might not inherit at all. `apply` (and spread) build a real argument list, so passing a very large array can exceed the engine's argument limit and throw a `RangeError`; for hundreds of thousands of elements, loop or chunk instead.

  • Now that spread syntax exists, is there any reason left to use apply?
    Rarely for the classic `Math.max` case — `Math.max(...nums)` is clearer. It still shows up when forwarding an entire argument list inside a generic wrapper, where you want to pass along both a receiver and an already-collected array in one expression. Note that both spread and `apply` build a real argument list, so a very large array can blow the engine's argument limit and throw a `RangeError`.
  • What happens to a primitive or null passed as the thisArg?
    It depends on the called function's mode. Strict-mode functions — which includes everything in an ES module or a class body — receive the value exactly as given, so `this` can genuinely be `null` or the number `7`. Sloppy-mode functions substitute `globalThis` for `null`/`undefined` and box primitives into wrapper objects, so `this` becomes a `Number` object instead.

saying these in an interview costs you the question

  • Says bind calls the function immediately like call
  • Claims apply and call differ in what this they set
  • Thinks bind mutates the original function
  • Assigns handler.call(obj) where a function value is needed
  • Believes call is faster or apply is deprecated

context

open as a page

In JavaScript, if you take a function returned by Function.prototype.bind and then call it with call, apply, or bind again, which this value wins?

level: middleimportance: must knowfreq 62%

basics

~20 s

The first bind wins. bind produces a hard-bound function whose receiver is permanent, so a later call, apply, or bind cannot override it — the extra thisArg is silently ignored, though extra arguments are still passed through.

open as a page

Why does Array.prototype.slice.call(arguments) turn the arguments object into a real array, and what replaces that idiom in modern JavaScript?

level: middleimportance: should knowfreq 48%

basics

~20 s

Array methods are specified as generic: they read only a length property and integer-keyed properties from whatever this they are given. call supplies the array-like arguments object as that this. Modern code uses a rest parameter, Array.from, or spread instead.

open as a page

How does Function.prototype.bind let you preset arguments as well as this, and what is the trap in its first parameter?

level: middleimportance: should knowfreq 45%

basics

~20 s

Any arguments after bind's first are stored and prepended to every later call, giving partial application. The trap is that the first parameter is always the this value, never an argument — so presetting only arguments requires passing a placeholder receiver such as null.

open as a page

You are writing a generic wrapper that logs every call to a method it is given. How do you make sure the wrapped method still receives the correct this, and where does that approach break down?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Return a regular function that invokes the target with fn.apply(this, args). The wrapper picks up the receiver from its own call site and forwards it. An arrow wrapper cannot do this, and calling fn(...args) drops the receiver entirely.

open as a page

What happens to the this value stored by Function.prototype.bind when the resulting function is invoked with the new operator?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

The bound this is ignored. Construction creates a fresh object and uses that as the receiver, so new is the one call form a hard binding cannot override. Bound arguments are still prepended, and instanceof against the target function still works.

open as a page