Function.prototype.apply Polyfill
Implement Function.prototype.apply from scratch — identical to call except arguments arrive as a single array.
JavaScript · Functions · Polyfills — Pratik Rai ·
Implement Function.prototype.bind from scratch, including partial application and the new-operator edge case that almost nobody gets right.
Function.prototype.bind returns a new function with this permanently fixed and, optionally, some leading arguments pre-filled. It is by far the hardest of the three context methods to reimplement, because unlike call and apply it does not invoke anything — it manufactures a function that has to behave correctly in situations you do not control, including being used with new.
call and apply are one-liners once you see the trick. bind is a genuine design problem. It has to handle partial application across two separate call sites, preserve constructor behaviour, and get length and name right on the function it returns. Almost every tutorial implementation gets the new case wrong, which makes it a reliable way for an interviewer to find out whether you understand what new actually does.
JSfile.javascript1function greet(greeting, name) { 2 return `${greeting}, ${name}! I am ${this.role}.`; 3} 4 5const bound = greet.bind({ role: 'admin' }, 'Hello'); 6bound('Ada'); // "Hello, Ada! I am admin."
Four properties matter:
this is fixed at bind time and cannot be overridden later — not by call, not by apply, not by a second bind.new, the bound this is ignored and the newly created object wins.length is the original's length minus the number of pre-bound arguments, floored at zero.JSfile.javascript1Function.prototype.myBind = function (thisArg, ...boundArgs) { 2 const fn = this; 3 return function (...callArgs) { 4 return fn.apply(thisArg, [...boundArgs, ...callArgs]); 5 }; 6};
This handles context and partial application correctly. It fails the constructor case:
JSfile.javascript1function Point(x, y) { this.x = x; this.y = y; } 2const BoundPoint = Point.myBind(null); 3const p = new BoundPoint(1, 2); 4p.x; // undefined — `this` was forced to null instead of the new object
new BoundPoint(...) creates a fresh object and passes it as this, but the inner apply overwrites it with thisArg. The instance is left empty, and p instanceof Point is false.
newThe fix is to detect construction and skip the bound this when it happens. The reliable signal is that during a new call, the inner function's this is an instance of the bound function:
JSfile.javascript1Function.prototype.myBind = function (thisArg, ...boundArgs) { 2 if (typeof this !== 'function') { 3 throw new TypeError('Bind must be called on a function'); 4 } 5 6 const targetFn = this; 7 8 function bound(...callArgs) { 9 const isConstructorCall = this instanceof bound; 10 return targetFn.apply( 11 isConstructorCall ? this : thisArg, 12 [...boundArgs, ...callArgs] 13 ); 14 } 15 16 // Inherit the prototype chain so `instanceof` still works. 17 if (targetFn.prototype) { 18 bound.prototype = Object.create(targetFn.prototype); 19 } 20 21 Object.defineProperty(bound, 'length', { 22 value: Math.max(0, targetFn.length - boundArgs.length), 23 configurable: true, 24 }); 25 Object.defineProperty(bound, 'name', { 26 value: `bound ${targetFn.name}`, 27 configurable: true, 28 }); 29 30 return bound; 31};
bound is a function declaration rather than an arrow so that it gets its own this — an arrow would capture the enclosing scope and the instanceof check would be meaningless.
The Object.create(targetFn.prototype) line is what makes new BoundPoint(1, 2) instanceof Point true. Assigning bound.prototype = targetFn.prototype directly would also work for instanceof, but it links the two prototypes so that mutating one affects the other.
Binding twice does nothing the second time. fn.bind(a).bind(b) is still bound to a. The second bind fixes this for the already-bound wrapper, and that wrapper ignores it. This surprises people who expect rebinding to work.
Arrow functions cannot be bound. They capture this lexically. bind returns a new function without error, but this inside it is unchanged. Same for call and apply.
Every bind allocates. Calling .bind(this) inside render creates a new function on every render, which breaks referential equality and defeats memoisation on child components. This is the practical reason React moved to class fields and hooks.
length is not just cosmetic. Currying utilities and some functional libraries inspect fn.length to decide whether they have enough arguments. Getting it wrong breaks them in ways that are hard to trace.
"What does new actually do?" The real question hiding inside this exercise. It creates an object whose prototype is the constructor's prototype, calls the constructor with that object as this, and returns it — unless the constructor returns an object of its own, which then wins.
"Implement call and apply too." Both are simpler, and the natural warm-up.
"How is this different from an arrow function in a class field?" A class field arrow captures this once per instance at construction; bind produces a new function per call unless you store it. Both solve the same problem with different allocation profiles.
bind returns a function; it does not invoke one.this instanceof bound and prefer the new object over the bound this.bound.prototype = Object.create(target.prototype) so instanceof survives.length shrinks accordingly.Goal: Implement myBind with partial application. Bonus: handle the `new` operator case.
Continue learning with these related challenges
Implement Function.prototype.apply from scratch — identical to call except arguments arrive as a single array.
JavaScript · Functions · Polyfills — Pratik Rai ·
Implement a Function.prototype.call polyfill from scratch. Master JavaScript this binding, execution context, primitive boxing, and safe property assignment techniques.
JavaScript · Functions · this — Pratik Rai ·
Implement Array.prototype.map from scratch. Master callback signatures, thisArg binding, and sparse-array hole preservation.
JavaScript · Arrays · Polyfills — Pratik Rai ·
Implement Function.prototype.apply from scratch — identical to call except arguments arrive as a single array.
JavaScript · Functions · Polyfills
Pratik Rai ·
Implement a Function.prototype.call polyfill from scratch. Master JavaScript this binding, execution context, primitive boxing, and safe property assignment techniques.
JavaScript · Functions · this
Pratik Rai ·
Implement Array.prototype.map from scratch. Master callback signatures, thisArg binding, and sparse-array hole preservation.
JavaScript · Arrays · Polyfills
Pratik Rai ·