Function.prototype.call implementation

What is call method

According to MDN docs the call() method of Function instances calls this function with a given thisArg value and arguments provided individually.

Args

  • It takes the thisArg as the first argument
  • and the arguments(optional, arg1...argN) for the function.

Return value

  • The result of calling the function with the specified this value and arguments.

Syntax:

// taken from mdn docs
call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, arg2, /* …, */ argN)

example -

function multiplyAge(multiplier = 1) {
  return this.age * multiplier;
}
 
const mary = {
  age: 21,
};
 
const john = {
  age: 42,
};
 
multiplyAge.myCall(mary); // 21
multiplyAge.myCall(john, 2); // 84
 

Implementation of our own call method -

1. Implementing using bind method

Function.prototype.myCall = function(thisArg, ...args) {
  const originalFn = this;
  return originalFn.bind(thisArg)(...args);
}

2. Implementing using Symbol

What if we don't want to use bind method?

If we carefully see what bind method do is it bound the environment of original function within the thisArg passed to it and return a new function which when called with arguments calls the original function within that environment with the arguments provided.

We can implement this functionality using Symbol.

Symbol would help us get the key which would be unique and do not clash with any existing properties on the object.

Function.prototype.myCall = function(thisArg, ...args) {
  const originalFn = this;
 
  // A unique symbol is created to use as a temporary property name.
  // Symbols are unique and do not clash with any existing properties on the object.
  const key = Symbol('func');
 
  let ctx = thisArg ?? window;
 
  // This ensures that ctx is always an object. 
  // If a primitive value (like a string or number) is passed, it is converted to its corresponding object type
  ctx = Object(ctx);
 
  ctx[key] = originalFn;
 
  // This allows the original function to be executed with ctx as its context.(added temporarily)
  const response = ctx[key](...args);
  delete ctx[key];
  return response;
}

Info

You can read more about Function.prototype.call() on mdn docs here