FossilsðŸ’ŧ CodingImplement bind, call, and apply
ðŸĶ–DinosaurJavaScriptthisFundamentals

Implement bind, call, and apply

These three tests whether you understand how this binding works at the implementation level — not just the API.

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 — boundArgs from bind time, callArgs from invocation
  • new detection — If bound function is called with new, ignore the bound context (spec behavior)
  • Prototype chain — Bound function inherits from original function's prototype (for instanceof to 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/undefined should default to global
  • Not wrapping primitives with Object() — call(42) should work
  • Missing new handling in bind — spec requires ignoring context when using new
  • Using a string property key instead of Symbol — may collide with existing properties