The new Operator
intermediateImplement myNew(Constructor, ...args): prototype linking, this binding, and the return-object override rule.
Implement Function.prototype.bind in JavaScript with partial application and correct new-operator handling — including the prototype link most polyfills get wrong.
Implement
Function.prototype.myBind(thisArg, ...boundArgs)returning a new function that (1) calls the original withthis = thisArg, (2) prependsboundArgsto call-time arguments, and (3) still works correctly with thenewoperator.
Requirements 1 and 2 are a closure exercise. Requirement 3 is the real question — it's where nearly every candidate (and a depressing number of blog polyfills) ships a bug that looks right and silently binds this to the wrong object.
Interviewers are evaluating: closures, this binding rules, prototype chains, and whether you actually test the edge case you claim to handle.
this — setTimeout(user.greet.bind(user), 1000); the bug class that made bind exist. (See the this keyword.)const log = console.log.bind(console, "[api]").this.handleClick = this.handleClick.bind(this) in every constructor.Function.prototype.myBind = function (thisArg, ...boundArgs) {
if (typeof this !== "function") {
throw new TypeError("myBind must be called on a function");
}
const targetFn = this;
function boundFn(...callArgs) {
// Was boundFn invoked with `new`? Then `this` is the freshly
// constructed object and must NOT be replaced by thisArg.
const calledWithNew = this instanceof boundFn;
return targetFn.apply(
calledWithNew ? this : thisArg,
[...boundArgs, ...callArgs]
);
}
// Link the prototype chain so `new boundFn()` instances are
// instanceof targetFn — and so the check above can even work.
if (targetFn.prototype) {
boundFn.prototype = Object.create(targetFn.prototype);
}
return boundFn;
};The popular broken version checks against the wrong function:
// ❌ BROKEN — copied all over the internet
return function (...callArgs) {
const calledWithNew = this instanceof targetFn; // wrong target!
return targetFn.apply(calledWithNew ? this : thisArg, [...boundArgs, ...callArgs]);
};Why it fails: new boundFn() creates an object whose prototype is boundFn.prototype — and if you never linked boundFn.prototype to targetFn.prototype, that object is not instanceof targetFn. The check is always false, so constructor calls silently bind to thisArg:
function Person(name, age) {
this.name = name;
this.age = age;
}
const BoundPerson = Person.brokenBind(null, "Charlie");
const p = new BoundPerson(30);
p.name; // undefined ❌ — Person ran against globalThis, not pWith the correct implementation (prototype link + this instanceof boundFn):
const BoundPerson = Person.myBind(null, "Charlie");
const p = new BoundPerson(30);
p.name; // "Charlie" ✅ boundArgs prepended
p.age; // 30 ✅ call-time args appended
p instanceof Person; // true ✅ prototype chain intactThis pairing — the prototype link makes the instanceof check possible — is the insight the question exists to test. State it explicitly.
new) pathfunction greet(greeting, punct) {
return `${greeting}, I'm ${this.name}${punct}`;
}
const alice = { name: "Alice" };
const hi = greet.myBind(alice, "Hi");
// closure captures: targetFn = greet, thisArg = alice, boundArgs = ["Hi"]
hi("!");
// boundFn called normally → this is undefined/globalThis, not instanceof boundFn
// → targetFn.apply(alice, ["Hi", "!"]) → "Hi, I'm Alice!"new after binding (the headline case above) — new wins over the bound this; bound arguments still apply.fn.bind(a).bind(b) keeps a. Your closure version gets this right for free: the inner bound function never lets b through. Worth saying aloud.this is a no-op (arrows have no own this), and new (arrow.bind()) throws because arrows aren't constructors.boundFn identity — native bound functions have name: "bound greet" and a length of target.length - boundArgs.length (floored at 0). A polyfill can patch both with Object.defineProperty; knowing they exist matters more than coding them.prototype on the target — arrow functions and methods ({ m() {} }) have no .prototype; hence the if (targetFn.prototype) guard.prototype property at all, and new walks through to the target's prototype at the engine level. Object.create is the closest userland approximation. Naming this gap honestly beats pretending the polyfill is exact.this instanceof targetFn check without the prototype link (silently always-false).boundFn.prototype at all — instances lose the target's methods.boundFn.prototype = targetFn.prototype directly — now mutating one mutates the other; Object.create adds the insulating layer.boundFn — arrows can't be new-ed and have no this of their own, so the constructor path is unimplementable.[...boundArgs, ...callArgs]).this instanceof boundFn and not new.target?" — new.target !== undefined is the modern, more precise check and works even when someone tampers with prototypes. Offer it as the upgrade.bind using only call/apply?" — you just did; the interviewer may then chain into implementing apply itself.this?" — see _.partial and currying.bind cost?" — one extra closure and one extra call frame per invocation; irrelevant almost always, measurable in hot paths (why React moved away from per-render binds).fn.bind(a).bind(b) ignore b?" — the outer bound function's this is already fixed inside a closure the second bind can't reach.Implement myNew(Constructor, ...args): prototype linking, this binding, and the return-object override rule.
Same trick as call but with an arguments array — plus the subtle differences that interviewers probe.
Walk the prototype chain by hand, then meet Symbol.hasInstance — and learn where instanceof lies to you.
Implement call from scratch: temporary method assignment and why Symbol keys avoid collisions.