Engrain by ByteRush

JS.03.03 Mid-level· 10 minCore — asked often

call, apply and bind in depth — and how to write bind yourself

call and apply run a function now with a chosen this; bind returns a new function. Learn partial application, why bound functions stay bound, and new on them.

Comes up in: JavaScript, Coding

Learn#

In an interview, Kunal is asked to write bind. He writes return () => fn.call(thisArg) and is asked three follow-ups he cannot answer: what about arguments, binding twice, and new?

All three methods choose this. fn.call(thisArg, a, b) and fn.apply(thisArg, [a, b]) run fn now; they differ only in how arguments are passed. fn.bind(thisArg, a) runs nothing. It returns a bound function with this fixed.

Arguments given to bind are fixed too, in front of later ones. That is partial application.

A bound function’s this cannot be changed again, not even by another bind.

call also lets you use one object’s method on another — method borrowing.

function intro(greeting, punct) { return `${greeting}, I am ${this.name}${punct}`; }
const asha = { name: "Asha" };
console.log(intro.call(asha, "Hi", "!"));
console.log(intro.apply(asha, ["Hello", "."]));
const hey = intro.bind(asha, "Hey");
console.log(hey("?"));
console.log(hey.bind({ name: "Ravi" })("!"));
console.log(Array.prototype.slice.call({ 0: "a", 1: "b", length: 2 }));

Output (verified)

Hi, I am Asha!
Hello, I am Asha.
Hey, I am Asha?
Hey, I am Asha!
[ 'a', 'b' ]
What bind storesStep 1 of 3

bound function

  • target: intro
  • this: asha
  • preset args: ['Hey']

Console

    empty

    intro.bind(asha, 'Hey') does not run intro. It returns a new bound function.

    Read the steps as text
    1. intro.bind(asha, 'Hey') does not run intro. It returns a new bound function.
    2. Calling it with '?' runs intro with this = asha and arguments ['Hey', '?'].
    3. Binding again creates a wrapper around the wrapper. The inner this = asha still wins.

    Predict#

    Predict first

    const f = intro.bind(asha); f.call({ name: 'Mei' }, 'Yo', '!') — what is returned?

    Interview angle#

    Say it like this — about 30 seconds

    “call and apply invoke a function immediately with a chosen this; call takes arguments one by one, apply takes an array. bind returns a new function with this and optionally leading arguments fixed — partial application. A bound this cannot be changed by later call or bind, but new ignores it and creates a normal instance. To implement bind, I return a function that merges preset and new arguments, uses apply, and checks new.target for the constructor case.”

    Stays on your device. Nothing is uploaded.
    Follow-up Implement Function.prototype.bind.
    Return a function that, when called normally, does fn.apply(thisArg, [...preset, ...args]); when called with new (new.target is set), returns new fn(...preset, ...args).
    Follow-up When would you use apply today?
    Rarely: spread syntax replaced most uses, as in Math.max(...nums). It still appears in wrappers that forward this and arguments.
    Follow-up What is method borrowing?
    Calling one object’s method on another, such as Array.prototype.slice.call(arrayLike). Array.from now covers that case.

    Practice#

    Timed, like the real round

    Write myBind(fn, thisArg, ...preset) in 20 minutes, as a standalone function (the prototype version is in JS.15.01).

    Done when

    • this is fixed, and preset arguments come before call-time arguments.
    • Binding the result again does not change this.
    • new on the result makes an instance of fn, ignoring the bound this.
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    How do call and apply differ?

    call takes arguments one by one; apply takes them as an array.

    What does bind return?

    A new function with this (and any preset arguments) fixed; it does not call the original.

    Can a second bind change a bound function's this?

    No. The first bound this wins.

    What happens with new on a bound function?

    The bound this is ignored; a new instance of the original function is created.

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    call/apply: run now, choose this. bind: run later, this and leading arguments fixed forever (except for new).

    Check yourself: Which of call, apply and bind does not run the function?

    bind.

    How it works underneathSenior rounds

    A bound function is an exotic object with [[BoundTargetFunction]], [[BoundThis]] and [[BoundArguments]]. Calling it calls the target with those values Source: ECMA-262: Bound function exotic objects. Its name is “bound ” plus the target’s name.

    Check yourself: Which internal slots does a bound function have?

    [[BoundTargetFunction]], [[BoundThis]] and [[BoundArguments]].

    Edge cases and trapsWhere people slip

    With new, the bound this is dropped, but preset arguments still apply:

    function Point(x, y) { this.x = x; this.y = y; }
    const AtX1 = Point.bind({ ignored: true }, 1);
    const p = new AtX1(2);
    console.log(p.x, p.y, p instanceof Point, "ignored" in p);

    Output (verified)

    1 2 true false
    Check yourself: Is an object made with new on a bound Point an instance of Point?

    Yes.

    In productionStaff-level answers

    Each bind creates a new function, so binding in a render or a loop breaks equality checks such as React.memo Source: MDN: Function.prototype.bind(). Bind once (constructor or field) or use stable callbacks. For partial application of pure functions, a small arrow is often clearer than bind(null, …).

    Check yourself: Why can bind inside render cause extra re-renders?

    It creates a new function each time, so props compare as changed.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • Implement Function.prototype.bind.