Array prototypes implementation

Photo by Ben Wicks on Unsplash

Array prototypes implementation

Introduction

Arrays in JavaScript are a special type of object which is mutable and can store multiple values. Underneath it is implemented as a Class which has methods to mutate array in its prototypes. We’ll be looking at some of the methods in this post and implementing them on our own. These implementation doesn’t change existing methods but provides a way to add our methods to them.

  • map
  • forEach
  • filter
  • reduce
  • reverse

Let’s understand what prototypes are and how we can use them here to create methods.

Prototypes

Every function and Object in JavaScript has a property named prototype. It consists of methods available on Object. It inherits them from the Object that is created. If we have to add more methods to an Object we add them as follows:

function Person() {
    this.name = "John"
    this.age = 26
}
Person.prototype.emailId = "john@doe.com"
Person.prototype.getContact = function() {
    return {name: this.name, email: this.emailId }
}

const p1 = new Person()
console.log(p1.getName())
// Output: { name: "John", email: "john@doe.com" }

this in function carries a value of properties available in the object. So whatever methods or properties a function/object can have, we can access them using this.

Implementing array methods

We’ll be using the above technique to add our custom methods to the array class. Since arrays are a global object, we can use this to get the array we are manipulating.

map

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

const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const output = input.myCustomMap(elem => {
  return 3*elem;
});

console.log(output); // [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30]

In the implementation above, we created myCustomMap method on Array. It takes the callback function as a parameter which takes the old value as an argument and returns a new value. We use the same index to store the new value in the results array.

forEach

Array.prototype.myCustomForEach = function (callback) {
  for (let i = 0; i < this.length; i++) {
      callback(this[i], i, this);
  }
}

const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

input.myCustomForEach(elem => {
  console.log(elem);
}); // 1 2 3 4 5 6 7 8 9 10

In the implementation above, we created myCustomForEach method that takes callback function as a parameter and iterates over elements of the array without returning anything. It returns undefined, unlike map method.

filter

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

let input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const output = input.myCustomFilter((elem) => {
  return elem % 2 === 0;
});

console.log(output); // [ 2, 4, 6, 8, 10 ]

In the implementation above, we created myCustomFilter method which takes callback function as a parameter and performs the callback function and for the values that is true, we return the result in new array. We return new array with elements by pushing elements without keeping them at same index.

reduce

The reduce function iterates through each element of the array and returns a single value. According to MDN docs, the first time that the callback is run there is no "return value of the previous calculation". If supplied, an initial value may be used in its place. Otherwise, the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0).

// Syntax
reduce(function(previousValue, currentValue){/* ... */}, initialValue)
Array.prototype.myCustomReduce = function (callback, initialValue) {
  let value = initialValue;

  for (let i = 0; i < this.length; i++) {
      value = callback(value, this[i]);
  }

  return value;
}

const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const sum = input.myCustomReduce((acc, elem) => {
    // acc stores value of previous return
  return acc + elem;
}, 0);

console.log(sum); // 55

reverse

Array.prototype.myCustomReverse = function () {
    const result = [];
    const lastIndex = array.length - 1;

    for (let index = lastIndex; index > -1; index -= 1) {
        const value = array[index];
        result[lastIndex - index] = value;
    }
    return result;
}

const input = [1, 'b', 'abc', { name: 'Jonh' }, 10];

console.log(input.myCustomReverse()); // [10, { name: 'Jonh' }, 'abc', 'b', 1]

In the reverse method, we iterate over the array in reverse, saving each value at [lastIndex - index] place in result array, which can be returned.

Conclusion

There is no better way to understand or learn something until we know how it works underneath. We have discussed how methods of arrays work internally, we can use them efficiently for our use-cases. I haven’t discussed sort in this post because implementing sort is a bit complicated for beginners. I’ll be covering it in a separate post.