skip to content

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%

answer

  1. arguments after the first are stored
  2. stored ones go in front
  3. the first slot is not an argument
  4. placeholder receiver for this-free functions

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.

solid answer

~40 s

`fn.bind(thisArg, a, b)` returns a function that, when called with `(c, d)`, invokes `fn` with `this === thisArg` and the argument list `(a, b, c, d)`. Bound arguments are always **prepended**, so you can only preset a *leading prefix* of the parameters — there is no way to fix the second parameter and leave the first open. The trap is the first slot: it is the receiver, not an argument. Writing `multiply.bind(2)` does not preset `2` as an argument, it makes `2` the receiver and presets nothing, which is a common and silent bug. For a function that ignores `this`, the idiom is `multiply.bind(null, 2)`. The returned function's `length` also shrinks by the number of bound arguments, since that many parameters are already satisfied.

code

javascript · 9 lines
javascript
function multiply(a, b) { return a * b; }

const double = multiply.bind(null, 2);
console.log(double(21));        // 42  -> multiply(2, 21)
console.log(double.length);     // 1   -> one parameter still open

// The trap: the first argument is the receiver, not a value for `a`
const broken = multiply.bind(2);
console.log(broken(21));        // NaN -> multiply(21, undefined)

go deeper

for a junior

Know the shape fn.bind(thisArg, arg) and be able to say that the first slot is the receiver, so presetting arguments alone needs a placeholder such as null.

for a middle

Explain that stored arguments are prepended on every invocation, that only a leading prefix can be fixed, and how the bound function's length changes as a result.

for a senior

Say when a closure beats bind — reordering, skipping or transforming arguments — and flag binding inside a hot path as needless allocation that also breaks identity-based lookups.

for a principal

Treat parameter order as part of the API contract: put stable, configuration-like parameters first so callers can partially apply, and decide whether your library ships pre-bound helpers or leaves that to consumers.

## Partial application in one built-in Partial application means fixing some of a function's arguments now and supplying the rest later. `bind` gives it to you directly, because every argument after the first is stored on the bound function and replayed on each invocation: ```js function multiply(a, b) { return a * b; } const double = multiply.bind(null, 2); double(21); // 42 -> multiply(2, 21) double(5); // 10 -> multiply(2, 5) ``` The bound function is reusable: the stored arguments are not consumed, they are prepended every single time it is called. ## The first parameter is always the receiver This is the part candidates get wrong. `bind`'s signature is `bind(thisArg, ...boundArgs)`. There is no overload where the first value is treated as an argument. So: ```js const wrong = multiply.bind(2); wrong(21); // 42? No - NaN in strict code, because it calls multiply(21, undefined) ``` `2` became the receiver, `multiply` never reads `this`, and only one argument arrived, so `b` is `undefined` and the result is `NaN`. Nothing throws; you just get a wrong number. The fix is to pass an explicit placeholder receiver: ```js const double = multiply.bind(null, 2); ``` `null` here is a convention meaning "this function does not use `this`". It is safe because `multiply` never touches `this`. If the target *does* read `this`, `null` is exactly the wrong choice — in strict-mode code (all modules and class bodies) `this` really will be `null` and the first property access throws `TypeError: Cannot read properties of null`. In that case pass the real receiver: `obj.method.bind(obj, arg)`. ## Only a leading prefix can be fixed Bound arguments are prepended, never merged positionally. There is no placeholder syntax that says "skip this parameter": ```js function slice(str, start, end) { return str.slice(start, end); } const fromZero = slice.bind(null, 'hello', 0); // fixes the first two fromZero(3); // 'hel' // Want to fix only `end`? bind cannot do it. Write a closure: const toThree = (str, start) => slice(str, start, 3); ``` This asymmetry drives real design decisions: if you expect callers to partially apply a function, order its parameters so the stable ones come first and the varying one comes last. ## What the returned function reports ```js function f(a, b, c) {} const g = f.bind(null, 1); g.length; // 2 - three declared parameters minus one bound g.name; // 'bound f' ``` `length` is the target's declared arity minus the count of bound arguments, clamped at zero, which keeps arity-introspecting code roughly honest. Note that declared arity already ignores default and rest parameters, so `length` was never an exact count of what a function accepts. ## Repeated binding accumulates arguments Because each `bind` wraps the previous result, argument prefixes compose even though the receiver does not: ```js function add3(a, b, c) { return a + b + c; } const a1 = add3.bind(null, 1); const a2 = a1.bind(null, 2); a2(3); // 6 ``` Each layer prepends its own stored arguments in order, so the final call sees `(1, 2, 3)`. ## When to reach for something else `bind` is the right tool when you want a receiver *and* a leading argument fixed in one expression, and when the result must be a plain function value you can hand to other code. A closure or an arrow wrapper is clearer when you need to reorder arguments, skip one, transform a value on the way through, or keep the ability to choose the receiver at each call — because a bound function's receiver can never be changed afterwards. Also remember that each `bind` call allocates a new function object, so building one inside a frequently-executed path creates garbage and destroys any identity-based caching.

  • Can you use bind to fix only the second parameter and leave the first open?
    No. Bound arguments are prepended in order, so `bind` can only fix a leading prefix of the parameter list, and the language offers no placeholder to skip a position. To fix a later parameter you need an ordinary wrapper — an arrow or function expression that calls the target with the arguments in the order you want.
  • When is passing null as bind's first argument a bug rather than an idiom?
    Whenever the target actually reads `this`. In strict-mode code — every module and class body — the receiver stays `null`, so the first property access throws a `TypeError`. In sloppy mode it is arguably worse: `null` becomes `globalThis`, so the call silently reads or writes global state. Pass the real receiver whenever the function uses one.

saying these in an interview costs you the question

  • Thinks bind's first argument is a preset parameter
  • Expects bound arguments to be appended, not prepended
  • Believes null as thisArg is always harmless
  • Claims bind can skip a parameter position
  • Says the bound arguments are consumed after one call

context