Polyfills

Polyfills In JavaScript

Polyfills

Back in the days of IE6 and Netscape, each browser had its own way of interpreting JavaScript. This inconsistency often broke websites across platforms. To bridge this gap, developers introduced a clever solution: polyfills.

A polyfill sometimes referred to as a Polyfiller, is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.

The term “polyfill” is a combination of “poly,” meaning many, and “fill,” indicating filling in the gaps.

Polyfills are used to bring new or standardized features to older browsers or environments that do not inherently support those features.

When new JavaScript features were introduced or when web standards evolve, not all browsers immediately implement those changes. This can create a sticky situation for developers where they want to use latest language features or APIs but still need to support older browsers. In such cases, they can include polyfills to ensure that the required functionality is available across a broader range of browsers.

Polyfills usually have two basic components: feature detection and feature implementation.

1 . Feature Detection

First, you have to check the need or it is required means to check whether the functionality of polyfill is already implemented, if it is then you don’t need to implement further just stops there. Otherwise, if the browser actually is missing the feature, you can proceed to the next step. It is similar to conditional support check.

This step is omitted in overriding polyfills where you override any existing behavior and instead use your implementation

This approach guarantees that every browser will behave the way you expect, but it has the disadvantage of causing potentially unnecessary overhead from overriding the native implementation of a feature.

2 . Feature Implementation

This is the meat of the polyfill where you actually implement the missing feature.

Polyfills Examples: Adding Prototype Methods

In ECMAScript 5, there were many new Array prototype methods added that emphasized a functional programming approach to manipulating arrays. An example of this is filter method.

Its signature involves accepting a user-defined callback function. The filter method does not modify the original array; instead, it returns a new array containing only the elements from the original array for which the callback function evaluates to true.

For example, you could filter an array to only contain even values.

const anotherArr = [1, 2, 3, 4, 5, 6]
if (!Array.prototype.myFilter) {
    Array.prototype.myFilter = function (userFn) {
        const result = [];
        for (let i = 0; i < this.length; i++) {
            if (userFn(this[i])) {
                result.push(this[i]);
            }
        }
        return result;
    }
}
console.log("myfilter", anotherArr.myFilter((e) => e % 2 == 0));
console.log("original Array",anotherArr);

Expected Output:

myfilter [ 2, 4, 6 ]

original Array [ 1, 2, 3, 4, 5, 6 ]

Visualization of the code

The filter method has an optional second parameter to bind to the this value of the function. For example, you could bind an object as this to the function passed to filter.

let fruits = {
  banana: "yellow",
  strawberry: "red",
  pumpkin: "orange",
  apple: "red"
};
let isRedFruit = function(name) {
  return this[name] === "red";
};
["pumpkin", "strawberry", "apple", "banana", "strawberry"].filter(isRedFruit, fruits);

Expected Output:

[ 'strawberry', 'apple', 'strawberry' ]

Since this was a feature added in ES5, older browsers, such as Internet Explorer 8 and below, do not support the filter method.

Example: Second Method (push)

Another light but vital array method among Array prototype methods, is push.
As it’s signature returns new length of array and adds value at the end. While it add value at the end of an array but it does not creates a new array like native push.

// Signature of push - returns new length of array and adds value at the end
if (!Array.prototype.mypush) {
    Array.prototype.mypush = function () {
        let length = this.length;  // Get the current array length

        // Loop through all arguments passed to mypush
        for (let i = 0; i < arguments.length; i++) {
            this[length] = arguments[i];  // Add each argument to the end of the array
            length++;                     // Increase the length counter
        }

        return length;  // Return the updated length of the array
    }
}
console.log("mypush", anotherArr.mypush(7, 8, 9));
console.log("original array", anotherArr);

Expected Output:

mypush 9

original array [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

We are getting the length of current array through this.length and storing it in a variable(which is length)

This is optional we can also do like this; in a more optimized way

if (!Array.prototype.mypush) {
    Array.prototype.mypush = function () {
        for (let i = 0; i < arguments.length; i++) {
            this[this.length] = arguments[i]; // Directly use this.length
        }
        return this.length; // Return the updated array length
    };
}

Expected Output:

mypush 9

original array [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Example: Third Method (map)

The map() method was introduced in ECMAScript 5 (ES5), released in 2009 with an intriguing functionality.

The map() method in JavaScript is used to transform each element of an array by applying a callback function, returning a new array without modifying the original one.

It takes a callback with up to three parameters: the current element, its index, and the original array.

For each element, map() executes the callback, collects the results, and returns an array of the same length.

For example:

if (!Array.prototype.mypush) {
    Array.prototype.mypush = function () {
        for (let i = 0; i < arguments.length; i++) {
            this[this.length] = arguments[i]; 
        }
        return this.length; 
    };
}

if (!Array.prototype.myMap) {
    Array.prototype.myMap = function (userFn) {
        const result = [];
        for (let i = 0; i < this.length; i++) {
            const value = userFn(this[i], i);
            result.mypush(value)
        }
        return result;
    }
};

console.log("mymap", anotherArr.myMap((v) => v * 2));
console.log("original array", anotherArr)

Expected Output:

mymap [ 2, 4, 6, 8, 10, 12, 14, 16, 18 ]

original array [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

In this example, if mypush method in prototype of Array prototype methods is undefined, and if so defines it by creating a function mypush which iterates over every argument passed to mypush and add each argument to the end of the array while at the same time update the length of the array.

Likewise, mymap function method creates a new array, applies a user-defined callback function (userFn) to each array element, and pushes the results into the new array using result.mypush(value).

Finally, it returns the transformed array without keeping the original one intact.

The map() method is supported by all modern browsers, including Chrome, Firefox, Safari, Edge, and Opera.

However, it is not supported in Internet Explorer 8 and earlier versions.


More Resources »

mdn webdocs

polyfill (article by Remy Sharp, the originator of the term)

greekforgreeks

Read More Blogs of mine

Conclusion

A Polyfill, or Polyfiller, is a piece of code (or plugin) that provides the technology that you, the developer, expect the browser to provide natively. They are used to provide modern features and changes that Some obsolete browser does not supports.