Back to JavaScript
JavaScript
easy
mid

How would you write a polyfill for Function.prototype.bind that supports new?

`bind` returns a new function with `this` pre-set and optional args pre-applied. Polyfill: closure capturing thisArg + preset args, returning a function that calls the original via `apply`. Handle `new`: when called as constructor, ignore thisArg and use the freshly constructed `this`. Set `bound.prototype = Object.create(fn.prototype)` so instanceof checks work.

2 min read·~10 min to think through

Cross-link to [[write-a-custom-implementation-of-functionprototypebind]] — same content, different slug.

Polyfill

js
if (!Function.prototype.myBind) {
  Function.prototype.myBind = function (thisArg, ...preset) {
    if (typeof this !== "function") throw new TypeError("not a function");
    const fn = this;
    function bound(...rest) {
      const isNew = this instanceof bound;
      return fn.apply(isNew ? this : thisArg, [...preset, ...rest]);
    }
    if (fn.prototype) bound.prototype = Object.create(fn.prototype);
    return bound;
  };
}

Tests

js
function greet(g, name) { return `${g}, ${name} (this=${this.tag})`; }
greet.myBind({ tag: "A" }, "Hi")("Sam");   // "Hi, Sam (this=A)"

function Point(x, y) { this.x = x; this.y = y; }
const BoundPoint = Point.myBind(null, 10);
const p = new BoundPoint(20);
p.x;                  // 10
p.y;                  // 20
p instanceof Point;   // true

Key spec behaviors covered

  • Throws TypeError if called on a non-function.
  • new boundFn() ignores the bound thisArg and constructs the original.
  • instance instanceof originalFn still works.
  • Preset args + call-time args concatenate.

Not covered (skip unless asked)

  • bound.length should be Math.max(0, fn.length - preset.length).
  • bound.name should be "bound " + fn.name.
  • Spec says re-binding doesn't change the original thisArg (our impl already preserves this via closure).

Why interviewers love this

It's a triple-tester: closures, this binding, prototype chain + new. Bonus signal if you handle the new case.

Interview framing

"Return a closure that calls fn.apply(thisArg, [...preset, ...rest]). The non-trivial part is the new case: when called as a constructor, the bound function should ignore thisArg and use the freshly created this. Detect with this instanceof bound and forward accordingly. Set bound.prototype = Object.create(fn.prototype) so instanceof checks still pass. Throw TypeError up front if called on a non-function. Spec niceties (bound.length, bound.name) usually skipped unless the interviewer probes."

Follow-up questions

  • What does new do on a bound function?
  • Why set bound.prototype?
  • How does our polyfill compare with native bind on length/name?

Common mistakes

  • Skipping the new case.
  • Not forwarding preset args.
  • Forgetting prototype setup.

Performance considerations

  • Closure allocation per bind. Cheap. Native is slightly faster due to engine intrinsics.

Edge cases

  • Non-function receiver (should throw).
  • Arrow functions ignore thisArg (lexical this).
  • Re-binding.

Real-world examples

  • Polyfill libraries (core-js), legacy IE support, React class binding patterns pre-arrow.

Senior engineer discussion

Seniors handle the new case and mention spec details. They'd recommend using native bind in production.

Related questions