JS Polyfills - Part 1 (call, apply, bind)

JS Polyfills - Part 1 (call, apply, bind)

·

3 min read

Any code we write, we always want it to be best and want it to work on every browser. But sometimes, our code might not work on older engines as they do on modern browsers. That's because the older engines don't understand latest features. So there's two ways we can tackle it. Use Transpilers & Polyfills.

Transpilers/Transcompilers are piece of software which can translates source code in modern/non-Javascript languages to javascript source code. Some examples are babel & traceur compilers for JS

What are Polyfills and origins:

  1. Poly: Solved by any number of ways.

  2. Fill: Can fill the holes in old browsers wherever needed with technology.

  3. Polyfill/polyfiller is a piece of code/plugin used to provide functionalities on older browsers that do not natively support it or browsers which may implement same features in different ways.

Why not use these polyfills exclusively then? For better functionality and performance. Native implementations of APIs can do more and are faster than polyfills. And also not to reinvent the wheel.

What Libraries can I use for filling these holes:

  1. Core js - includes needed features

  2. polyfill.io - provides script with polyfills.

Where can I find browser support/compatibility details for different features:

  1. https://kangax.github.io/compat-table/es6/ – for pure JavaScript. https://caniuse.com/ – for browser-related functions

Let's see how some of the functions we use extensively work under the hood!

1. call()

  • Function: call(thisArg, ...args)

  • Usage: fn.call(currentContext, arg1, arg2, argN)

  • Description: Does function borrowing ie; Borrow functions from other objects and use that data on other objects

  • Polyfill: Call

Function.prototype.customCall = function (currentThis = {}, ...args) {
  // check if current context is pointing to a function
  if (typeof this !== 'function') {
    throw new Error(this + 'cannot call')
  }
  currentThis.fnName = this;
  currentThis.fnName(...args);
};

2. apply()

  • Function: apply(thisArg = {}, ...args = [])

  • Usage: fn.call(currentContext, [arg1, arg2, argN])

  • Description: Just like call, does function borrowing but the arguments are passed as an array

  • Polyfill:Apply

Function.prototype.customApply = function (currentThis = {}, args = []) {
  // check if provided arguments is an array
  if (!Array.isArray(args)) {
    throw new Error(this + 'Invalid argument type')
  }
  // check if current context is pointing to a function
  if (typeof this !== 'function') {
    throw new Error(this + 'cannot call')
  }
  currentThis.fnName = this;
  currentThis.fnName(...args);
};

3. bind()

  • Function: bind(thisArg = {}, ...args = [])

  • Usage: fn.bind(currentContext, [arg1, arg2, argN])

  • Description: Returns a new function with new "this" context.

  • Polyfill: Bind

Function.prototype.customBind = function (...args) {
  const currContext = this;
  // Get all arguments except 1st as 1st is context 
  let params = args.slice(1);
  //Bind returns copy of the function & can have new args passed to the invoking function
  return function (...arguments) {
    //args[0] is the new context and new arguments provided while binding and invoking
    currContext.apply(args[0], [...params, ...arguments]);
  };
}

Stay tuned for Part 2 Keep learning!

Find more polyfills @ Github: JS Polyfills