Implement bind, call, and apply
Interview Question: "Implement Function.prototype.bind from scratch."
Implement call
Function.prototype.myCall = function(context, ...args) {
context = context ?? globalThis;
context = Object(context);
const fnKey = Symbol();
context[fnKey] = this;
const result = context[fnKey](...args);
delete context[fnKey];
return result;
};How it works: Temporarily attaches the function as a method of the context object. When called as context[fnKey](), implicit binding makes this = context. The Symbol key prevents collisions with existing properties.
Implement apply
Function.prototype.myApply = function(context, args = []) {
context = context ?? globalThis;
context = Object(context);
const fnKey = Symbol();
context[fnKey] = this;
const result = context[fnKey](...args);
delete context[fnKey];
return result;
};Only difference from call: arguments come as an array.
Implement bind
Function.prototype.myBind = function(context, ...boundArgs) {
const fn = this;
const bound = function(...callArgs) {
const isNewCall = this instanceof bound;
return fn.apply(
isNewCall ? this : context,
[...boundArgs, ...callArgs]
);
};
bound.prototype = Object.create(fn.prototype);
return bound;
};Key points:
- Partial application â
boundArgsfrom bind time,callArgsfrom invocation newdetection â If bound function is called withnew, ignore the bound context (spec behavior)- Prototype chain â Bound function inherits from original function's prototype (for
instanceofto work)
Usage
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const user = { name: 'Alice' };
greet.myCall(user, 'Hello', '!'); // "Hello, Alice!"
greet.myApply(user, ['Hi', '?']); // "Hi, Alice?"
const bound = greet.myBind(user, 'Hey');
bound('.'); // "Hey, Alice."Common Mistakes
- Forgetting
context ?? globalThisânull/undefinedshould default to global - Not wrapping primitives with
Object()âcall(42)should work - Missing
newhandling in bind â spec requires ignoring context when usingnew - Using a string property key instead of Symbol â may collide with existing properties