Implement Function.prototype.bind
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 thisvalue to bind for normal calls (ignored when called withnew).boundArgs: any[] —Arguments to pre-apply to the function (partial application).
Returns
Function — Solution idea
Goal: model the core call binding, partial arguments, and classic function-constructor behavior without claiming full native equivalence.
// 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; // => trueSolution
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.
Approach: Bound wrapper with constructor detection (recommended)
Idea
Return a wrapper function boundFn that:
- Merges
boundArgswithcallArgs. - Uses
new.targetto distinguishnew boundFn()from an ordinary call. - Applies the target to the new receiver for the supported constructor case and to
thisArgotherwise.
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
- `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.
- `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).
- 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
Similar questions
Guides
Preparing for interviews? Use Frontend Coding Challenges first, then move into a concrete Study Plan before targeted Company Prep.