machine coding11
javascript fundamentals
thisprototypespolyfills

Polyfill call and apply

Implement Function.prototype.call and Function.prototype.apply yourself.

medium1 min readsolution

What it tests

Whether you really understand this binding, or have only memorised the rules. The trick is that you cannot use call/apply/bind to write them — you have to bind this some other way.

The approach

Attach the function as a temporary property of the target object, call it as a method so the implicit binding does the work, then remove it:

Function.prototype.myCall = function (context, ...args) {
  context = context || globalThis;
  const key = Symbol("fn");
  context[key] = this;
  const result = context[key](...args);
  delete context[key];
  return result;
};

apply is the same thing with the arguments arriving as an array.

Where it usually goes wrong

  • Using a string key. context.fn = this clobbers a real fn property if the object has one. A Symbol can't collide.
  • Not returning the result. Easy to forget once delete is in the way.
  • Forgetting primitives and null. Non-strict call(null) binds the global object, and primitives get wrapped.

Full solution

2 files from src/folders/polyfills.

apply.js

const first = {
  name: "sourav",
};
 
function printNames(a, b) {
  return this.name + " " + a + " " + b;
}
Function.prototype.myApply = function (thisArgs, args = []) {
  const self = thisArgs || globalThis;
  const key = Symbol();
  self[key] = this;
 
  const result = self[key](...args);
  delete self[key];
  return result;
};
 
console.log(printNames.myApply(first, ["hi", "there"]));

call.js

const villan = {
  name: "sourav",
};
 
function SayName() {
  console.log(this.name);
}
 
function myCall(fn, thisArgs, ...args) {
  thisArgs.fn = fn;
  const result = thisArgs.fn(...args);
  delete thisArgs.fn;
  return result;
}
 
myCall(SayName, villan);
 
Function.prototype.myCall = function (thisArgs, ...args) {
  const key = Symbol();
  thisArgs[key] = this;
  const result = thisArgs[key](...args);
  delete thisArgs[key];
  return result;
};
 
Function.prototype.myCall = function (thisArgs, ...args) {
  const self = thisArgs || globalThis;
  const key = Symbol();
  self[key] = this;
  const result = self[key](...args);
  delete self[key];
  return result;
};
 
Function.prototype.myCall = function (thisArgs, ...args) {
  return this.apply(thisArgs, args);
};
share this post