FrontendAtlas
Interview Questions
Home>JavaScript interview questions> JavaScript coding challenges >Implement Function.prototype.bind

Implement Function.prototype.bind

hard
By FrontendAtlas Editorial · Updated Jul 14, 2026
Implement a deliberately scoped myBind(fn, thisArg, ...boundArgs) exercise. It must bind this for ordinary calls, support partial application, and support new for classic function constructors whose prototype is an object. Constructor calls must be detected with new.target, not by inspecting the receiver. This helper is not a complete Function.prototype.bind polyfill: ES classes, constructors that depend on new.target, bound-function exotic behavior, and native name, length, prototype, and Symbol.hasInstance semantics are outside the contract.

Arguments

  • fn: Function — The target function to bind.
  • thisArg: any — The this value to bind for normal calls (ignored when called with new).
  • boundArgs: any[] — Arguments to pre-apply to the function (partial application).

Returns

Function — A wrapper with bound-call and partial-application behavior plus the documented classic-constructor subset.
Examples
// Example 1: bind `this`
function getX() { return this.x; }
const obj = { x: 42 };
const bound = myBind(getX, obj);
bound(); // => 42

// Example 2: partial application
function add(a, b, c) { return a + b + c; }
const add5 = myBind(add, null, 2, 3);
add5(10); // => 15

// Example 3: `new` must ignore thisArg
function Person(name) { this.name = name; }
Person.prototype.say = function() { return this.name; };
const BoundPerson = myBind(Person, { name: 'SHOULD_NOT_USE' });
const p = new BoundPerson('Ada');
p.name; // => 'Ada'
p.say(); // => 'Ada'
p instanceof Person; // => true
p instanceof BoundPerson; // => true

Solution

Overview

Goal: model the core call binding, partial arguments, and classic function-constructor behavior without claiming full native equivalence.

Key rule: new.target is the reliable signal that the wrapper itself was invoked with new; a receiver can inherit from boundFn.prototype during an ordinary .call(...) and must not be misclassified. During supported constructor calls, ignore the bound thisArg and use the newly created instance.

Prototype rule: for classic function constructors with object prototypes, instances created by new boundFn() should be instances of the original fn and of boundFn. ES classes, new.target-sensitive constructors, bound-function exotic behavior, and native metadata/prototype/Symbol.hasInstance equivalence are explicitly outside this exercise.

1

Approach: Bound wrapper with constructor detection (recommended)

Idea

Return a wrapper function boundFn that:

  • Merges boundArgs with callArgs.
  • Uses new.target to distinguish new boundFn() from an ordinary call.
  • Applies the target to the new receiver for the supported constructor case and to thisArg otherwise.

Handling new

When called with new, JavaScript creates this as a fresh object whose prototype is boundFn.prototype. Forward that receiver into a classic function constructor. Do not use this instanceof boundFn as the signal: an ordinary caller can supply an object that inherits from boundFn.prototype.

Prototype preservation

For a classic constructor with an object prototype, set boundFn.prototype to an object that delegates to fn.prototype. This is an educational subset, not the exotic bound-function object created by native bind.

Complexity

  • Time: O(k) where k is total args merged.
  • Space: O(k) for the merged argument list plus the stored bound arguments.
export default function myBind(fn, thisArg, ...boundArgs) {
  if (typeof fn !== 'function') {
    throw new TypeError('myBind: fn must be a function');
  }

  function boundFn(...callArgs) {
    const thisToUse = new.target ? this : thisArg;
    return fn.apply(thisToUse, [...boundArgs, ...callArgs]);
  }

  // This prototype bridge supports the documented classic-constructor subset.
  if (fn.prototype && (typeof fn.prototype === 'object' || typeof fn.prototype === 'function')) {
    boundFn.prototype = Object.create(fn.prototype);
    Object.defineProperty(boundFn.prototype, 'constructor', {
      value: boundFn,
      writable: true,
      configurable: true
    });
  }

  return boundFn;
}
export default function myBind<T extends (...args: any[]) => any>(
  fn: T,
  thisArg: any,
  ...boundArgs: any[]
): (...callArgs: any[]) => ReturnType<T> {
  if (typeof fn !== 'function') {
    throw new TypeError('myBind: fn must be a function');
  }

  function boundFn(this: any, ...callArgs: any[]): ReturnType<T> {
    const thisToUse = new.target ? this : thisArg;
    return fn.apply(thisToUse, [...boundArgs, ...callArgs]) as ReturnType<T>;
  }

  // This prototype bridge supports the documented classic-constructor subset.
  const prototype = (fn as any).prototype;
  if (prototype && (typeof prototype === 'object' || typeof prototype === 'function')) {
    (boundFn as any).prototype = Object.create(prototype);
    Object.defineProperty((boundFn as any).prototype, 'constructor', {
      value: boundFn,
      writable: true,
      configurable: true
    });
  }

  return boundFn as any;
}

Notes & Pitfalls

Pitfalls
  • `thisArg` must be ignored when the bound function is used with `new`.
  • If you set `boundFn.prototype = fn.prototype`, you will mutate/alias the original prototype; use `Object.create(fn.prototype)` instead.
  • `instanceof` behavior depends on the prototype chain; missing prototype wiring makes `p instanceof Person` fail.
  • This scoped helper excludes ES classes, constructors that inspect `new.target`, bound-function exotic behavior, and native `name`, `length`, `prototype`, and `Symbol.hasInstance` equivalence.
Edge cases
  • `thisArg` can be `null`/`undefined` (non-strict functions will default `this` to global; strict keeps it as provided).
  • A function without an object prototype (for example, an arrow) is supported only for ordinary bound calls, not construction.
  • Constructor functions that explicitly return an object: `new` should return that object (native JS behavior).
Techniques
  • Detect wrapper construction via `new.target`.
  • Preserve prototype chain via `Object.create(fn.prototype)`.
  • Apply partial args by concatenating `[...boundArgs, ...callArgs]`.

Common mistakes on this challenge

  • myBind must handle normal calls and constructor calls differently

    This scoped helper needs argument pre-binding plus reliable classic-constructor detection and prototype preservation.

    • Return a wrapper that applies `fn` with bound args plus call-time args.
    • Use `new.target` inside the wrapper; do not infer construction from `this instanceof boundFn`.
    • When the wrapper is constructed, ignore `thisArg` and use the new instance.
    • Bridge an object-valued `fn.prototype` for the documented classic-constructor subset; classes and native bound-function exotic semantics are out of scope.

Resources

  • MDN – Function.prototype.bind
  • MDN – Object.create

Similar questions

Implement the `new` OperatorhardCreate a Spy Function (Test Double)intermediateCreate Object with Prototypeeasy

Guides

Frontend interview preparation guideGuideFrontend coding interview questions and prep guideBlueprintJavaScript Problems That Actually Show UpBlueprintBuild Great UI in 60 MinutesBlueprint

Preparing for interviews? Use Frontend Coding Challenges first, then move into a concrete Study Plan before targeted Company Prep.

Open frontend interview questionsBrowse JavaScript interview questionsOpen Essential 60Open Machine Coding HubOpen Frontend Coding ChallengesOpen System DesignOpen Interview Prep GuideOpen System Design BlueprintOpen Framework Prep PathsOpen Study PlansOpen JavaScript mastery study planOpen Company PrepOpen JavaScript Framework Prep Guide
↗Incidents hub
19 / 88