Polyfills of Array Methods in JavaScript

Polyfills of Array Methods in JavaScript

Table of contents

No heading

No headings in the article.

Introduction:

JavaScript arrays are fundamental data structures that offer a wide range of functionalities. However, the native JavaScript array methods might not always cover all the requirements of your project. That's where polyfills come to the rescue. In this article, we will explore some powerful JavaScript array polyfills that extend the capabilities of arrays and provide enhanced functionalities.

A polyfill (or polyfiller) is a piece of code (or plugin) that provides the technology that we the, developers, expect the browser to provide natively.

In this article, I've grouped array methods polyfills into 5 basic categories according to their functionalities.

  1. Access and Manipulation:

    ★ includes(): Check if an element exists in an array or not.

    Polyfill code:

     Array.prototype.includes = function (element, fromIndex = 0) {
       for (let i = fromIndex; i < this.length; i++) {
         if (this[i] === element) {
           return true;
         }
       }
       return false;
     };
    

    ★ indexOf(): Get the index of the first occurrence of an element in an array. Polyfill code:

     Array.prototype.indexOf = function (element, fromIndex = 0) {
       for (let i = fromIndex; i < this.length; i++) {
         if (this[i] === element) {
           return i;
         }
       }
       return -1;
     };
    

    ★ lastIndexOf(): Get the index of the last occurrence of an element in an array. Polyfill code:

     Array.prototype.lastIndexOf = function (
       element,
       fromIndex = this.length - 1
     ) {
       for (let i = fromIndex; i >= 0; i--) {
         if (this[i] === element) {
           return i;
         }
       }
       return -1;
     };
    

    ★ concat(): Concatenate two or more arrays into one.

    Polyfill code:

     Array.prototype.concat = function () {
       let result = [];
    
       for (let i = 0; i < this.length; i++) {
         result.push(this[i]);
       }
    
       for (let i = 0; i < arguments.length; i++) {
         if (Array.isArray(arguments[i])) {
           const dummyArr = arguments[i];
           for (let i = 0; i < dummyArr.length; i++) {
             result.push(dummyArr[i]);
           }
         } else {
           result.push(arguments[i]);
         }
       }
    
       return result;
     };
    

    ★ join(): Join the elements of an array into a string.

    Polyfill code:

     Array.prototype.join = function (separator = ",") {
       let result = "";
    
       for (let i = 0; i < this.length; i++) {
         if (i === this.length - 1) {
           result += this[i];
         } else {
           result += this[i] + separator;
         }
       }
    
       return result;
     };
    

    ★ slice(): Create a new array that is a slice of the original array.

    Polyfill code:

      Array.prototype.slice = function(start, end, count) {
         if (start === undefined) {
           start = 0;
         }
    
         if (end === undefined) {
           end = this.length;
         }
    
         if (count === undefined) {
           count = end - start;
         }
    
         let result= [];
         for (let i = start; i < end && i < this.length; i++) {
           result.push(this[i]);
         }
    
         return result;
       };
    

    ★ valueof(): Returns the primitive value of array.

    Polyfill code:

       Array.prototype.valueOf = function() {
         return this;
       };
    

    ★ splice(): Insert or remove elements from an array.

    Polyfill code:

      Array.prototype.splice = function(index, deleteCount, items) {
         if (deleteCount === undefined) {
           deleteCount = this.length - index;
         }
    
         let removed = [];
         for (let i = index; i < index + deleteCount; i++) {
           removed.push(this[i]);
         }
    
         for (let i = index; i < this.length; i++) {
           this[i] = this[i + deleteCount];
         }
    
         if (items !== undefined) {
           for (let i = 0; i < items.length; i++) {
             this[index + i] = items[i];
           }
         }
    
         return removed;
       };
    
  2. Manipulation & Retrieval :

    ★ push(): Add an element to the end of an array.

    Polyfill code:

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

    ★ pop(): Remove the last element from an array.

    Polyfill code:

     Array.prototype.pop = function () {
       if (this.length > 0) {
         let lastElement = this[this.length - 1];
         this.length -= 1;
         return lastElement;
       }
     };
    

    ★ shift(): Remove the first element from an array.

    Polyfill code:

     Array.prototype.shift = function () {
       if (this.length > 0) {
         const firstElement = this[0];
    
         for (let i = 0; i < this.length; i++) {
           this[i] = this[i + 1];
         }
    
         this.length -= 1;
    
         return firstElement;
       }
     };
    

    ★ unshift(): Add an element to the beginning of an array.

    Polyfill code:

     Array.prototype.unshift = function () {
       if (arguments.length > 0) {
         // move elements of the array ahead
         for (let i = this.length - 1; i >= 0; i--) {
           this[i + arguments.length] = this[i];
         }
    
         // add the args elements at the start
         for (let i = 0; i < arguments.length; i++) {
           this[i] = arguments[i];
         }
       }
    
       return this.length;
     };
    
  3. Element Iteration and Searching:

    ★ forEach(): Execute a function for each element in an array.

    Polyfill code:

     Array.prototype.forEach = function (callback) {
       for (let i = 0; i < this.length; i++) {
         if (typeof this[i] !== "undefined") {
           callback(this[i], i, this);
         }
       }
     };
    

    ★ map(): Create a new array by applying a function to each element in the original array.

    Polyfill code:

     Array.prototype.map = function (callback) {
       let result = [];
    
       for (let i = 0; i < this.length; i++) {
         const value = callback(this[i], i, this);
         result.push(value);
       }
    
       return result;
     };
    

    ★ filter(): Create a new array by filtering out elements from the original array that do not meet certain criteria.

    Polyfill code:

     Array.prototype.filter = function (callback) {
       let result = [];
    
       for (let i = 0; i < this.length; i++) {
         if (callback(this[i], i, this)) {
           result.push(this[i]);
         }
       }
    
       return result;
     };
    

    ★ find(): Return the first element in an array that meets certain criteria.

    Polyfill code:

      Array.prototype.find = function(callback) {
         if (!callback) {
           throw new TypeError('callback must be a function');
         }
    
         for (let i = 0; i < this.length; i++) {
           if (callback.call(this, this[i])) {
             return this[i];
           }
         }
    
         return undefined;
       };
    

    ★ findIndex(): Return the index of the first element in an array that meets certain criteria.

    Polyfill code:

      Array.prototype.findIndex = function(callback) {
         if (!callback) {
           throw new TypeError('callback must be a function');
         }
    
         let index = -1;
         for (let i = 0; i < this.length; i++) {
           if (callback.call(this, this[i])) {
             index = i;
             break;
           }
         }
    
         return index;
       };
    

    ★ some(): Return true if any element in an array meets certain criteria.

    Polyfill code:

     Array.prototype.some = function(callback) {
         if (!callback) {
           throw new TypeError('callback must be a function');
         }
    
         for (let i = 0; i < this.length; i++) {
           if (callback.call(this, this[i])) {
             return true;
           }
         }
    
         return false;
       };
    

    ★ every(): Return true if all elements in an array meet certain criteria.

    Polyfill code:

       Array.prototype.every = function(callback) {
         if (!callback) {
           throw new TypeError('callback must be a function');
         }
    
         for (let i = 0; i < this.length; i++) {
           if (!callback.call(this, this[i])) {
             return false;
           }
         }
    
         return true;
       };
    
  4. Transformation:

    ★ reduce(): Reduce an array to a single value by applying a function to each element.

    Polyfill code:

     Array.prototype.reduce = function(callback, initialValue) {
         if (!callback) {
           throw new TypeError('callback must be a function');
         }
    
         let accumulator = initialValue;
         for (let i = 0; i < this.length; i++) {
           accumulator = callback.call(this, accumulator, this[i]);
         }
    
         return accumulator;
       };
    

    ★ reduceRight(): Reduce an array to a single value by applying a function to each element in reverse order.

    Polyfill code:

      Array.prototype.reduceRight = function(callback, initialValue) {
         if (!callback) {
           throw new TypeError('callback must be a function');
         }
    
         let accumulator = initialValue;
         for (let i = this.length - 1; i >= 0; i--) {
           accumulator = callback.call(this, accumulator, this[i]);
         }
    
         return accumulator;
       };
    

    ★ reverse(): Reverse the order of the elements in an array.

    Polyfill code:

     Array.prototype.reverse = function() {
         let length = this.length;
         for (let i = 0, j = length - 1; i < j; i++, j--) {
           let temp = this[i];
           this[i] = this[j];
           this[j] = temp;
         }
    
         return this;
       };
    

    ★ sort(): Sort the elements in an array.

    Polyfill code:

       Array.prototype.sort = function(compareFn) {
         if (!compareFn) {
           compareFn = function(a, b) {
             if (a < b) {
               return -1;
             } else if (a > b) {
               return 1;
             } else {
               return 0;
             }
           };
         }
    
         for (let i = 0; i < this.length; i++) {
           for (let j = i + 1; j < this.length; j++) {
             if (compareFn(this[i], this[j]) > 0) {
               let temp = this[i];
               this[i] = this[j];
               this[j] = temp;
             }
           }
         }
    
         return this;
       };
    
  5. Length and Initialization:

    ★ length(): Get the number of elements in an array.

    Polyfill code:

       Array.prototype.length = function() {
         return this.reduce(function(a, b) {
           return a + 1;
         }, 0);
       };
    

    ★ fill(): Fill an array with a specified value.

    Polyfill code:

     Array.prototype.fill = function (value, start = 0, end = this.length) {
       if (start < 0) {
         start = this.length + start;
       }
    
       if (end < 0) {
         end = this.length + end;
       }
    
       for (let i = start; i < end; i++) {
         this[i] = value;
       }
    
       return this;
     };
    

    ★ copyWithin(): Copy elements from one part of an array to another part.

    Polyfill code:

     Array.prototype.copyWithin = function (
       target = 0,
       start = 0,
       end = this.length
     ) {
       if (target < 0) {
         target = this.length + target;
       }
    
       if (start < 0) {
         start = this.length + start;
       }
    
       if (end < 0) {
         end = this.length + end;
       }
    
       for (let i = start; i < end && target < this.length; i++) {
         this[target] = this[i];
         target++;
       }
    
       return this;
     };
    

    ★ Array.from(): Create an array from an iterable object.

    Polyfill code:

       Array.from = function(iterable, mapFn, thisArg) {
         if (typeof iterable !== 'iterable') {
           throw new TypeError('iterable must be iterable');
         }
    
         let array = [];
    
         if (mapFn) {
           iterable.forEach(function(value) {
             array.push(mapFn.call(thisArg, value));
           });
         } else {
           for (let i = 0; i < iterable.length; i++) {
             array.push(iterable[i]);
           }
         }
    
         return array;
       };
    

    ★ toString(): Convert an array to a string.

    Polyfill code:

     Array.prototype.toString = function() {
         if (this === null) {
           throw new TypeError("Cannot convert null or undefined to object");
         }
    
         let obj = Object(this);
         let len = obj.length >>> 0;
    
         if (len === 0) {
           return "";
         }
    
         let separator = ",";
         let result = obj[0] === undefined ? "" : String(obj[0]);
    
         for (let i = 1; i < len; i++) {
           result += separator + (obj[i] === undefined ? "" : String(obj[i]));
         }
    
         return result;
       };
    

    This is how the custom implementation of array methods works & also a good starting point where you can learn how JavaScript under the hood creates its inbuilt methods implementation and works. You can create your Polyfills or custom methods like this and attach them to the prototype chain to make it available to the reference or abstract class used inside the JavaScript environment as well.

    Thank you for reading! Happy coding!