Implement JavaScript Array Methods From Scratch

zagaris

Aris Zagakos

Posted on December 5, 2021

Implement JavaScript Array Methods From Scratch

Table of Contents

  1. Introduction
  2. prototype
  3. this
  4. Array Methods
  5. Resources

Introduction

The JavaScript Array class is a global object that is used in the construction of arrays. Array is a special type of object that is mutable and it is used to store multiple values.

In this article, we will implement our own array methods from scratch. These implementations don't intend to replace the existing methods but to provide a better understanding of how these methods work and their uses.

Methods Description
indexOf() Returns the first index at which a given element can be found in the array, otherwise returns -1.
lastIndexOf() Returns the last index at which a given element can be found in the array, otherwise returns -1.
reverse() Returns the reversed array.
forEach() Executes a provided function once for each array element.
map() Creates a new array with the results of calling a provided function on every element in the calling array.
filter() Creates a new array with all elements that pass the test implemented by the provided function.
reduce() Applies a function against an accumulator and each element in the array to reduce it to a single value.

For a better understanding of Higher Orders Functions and specifically map(), filter() and reduce() methods you can check this article.

Before we start to implement these methods, we will take a quick look on how prototype and this work.

What is prototype?

In JavaScript, every function and object has a property named prototype by default. Prototypes are the mechanism by which JavaScript objects inherit methods and properties with each other. Prototypes are very useful when we want to add new properties to an object which will be shared across all the instances.

function User () {
    this.name = 'George',
    this.age = 23
}

User.prototype.email = 'george@email.com';
User.prototype.userInfo = function () {
    console.log('[User name]: ', this.name, ' [User age]: ', this.age);
}

const user = new User();

console.log(user.email); // george@email.com

user.userInfo(); // [User name]:  George  [User age]:  23

Enter fullscreen mode Exit fullscreen mode

In the example above, we create the function object User that has the properties name and age. Then, we access the User function object with prototype property and we add the property email and the function userInfo() to it.

What is this?

The value of this is determined by the object that currently owns the space that this keyword is in (runtime binding).

function User () {
    this.name = 'George',
    this.age = 23,
    this.printInfo = function() {
        console.log(this);
    }
    this.orders = {
        orderId: '12345',
        printOrderId: function() {
            console.log(this);
        }
    }
}

const user = new User();

user.printInfo(); // User { name: 'George', age: 23, printInfo: [Function], orders: { orderId: '12345', printOrderId: [Function: printOrderId] } }

user.orders.printOrderId(); // { orderId: '12345', printOrderId: [Function: printOrderId] }
Enter fullscreen mode Exit fullscreen mode

In the example above, we use again the function object User and add the object orders to it. The user.printInfo() prints the this value and in this case it contains all the properties of the User function object. The user.orders.printOrderId() prints only the properties of the orders object and that happens because the method printOrderId() is called through the orders object.

Let's implement the Array Methods

In order to implement the methods, we will access the Array object via prototype property and then we will add our new methods. The this keyword inside the methods has the value of the array that is calling the corresponding array method.

Custom indexOf

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

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

console.log(output.customIndexOf(2)); // 1
Enter fullscreen mode Exit fullscreen mode

In the example above, the customIndexOf method takes as a parameter a value and then we iterate the array until we find the corresponding value and return its index.

Custom lastIndexOf

Array.prototype.customLastIndexOf = function (value) {
    for (let i = this.length - 1; i >= 0; i--) {
        if (this[i] == value)
            return i;        
    }
    return -1;
}

const output = [1, 2, 3, 4, 5, 9, 7, 9, 9, 10];

console.log(output.customLastIndexOf(9)); // 8
Enter fullscreen mode Exit fullscreen mode

In the example above, the customLastIndexOf method takes as a parameter a value and then we iterate the array until we find the last corresponding value and return its index.

Custom reverse

Array.prototype.customReverse = function () {
    let left = 0;
    let right = this.length - 1;

    while(left < right) {
        let temp = this[left];
        this[left] = this[right];
        this[right] = temp;
        left++;
        right--;
    }
    return this;
}

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

console.log(output.customReverse()); // [10, { name: 'Jonh' }, 'abc', 'b', 1]
Enter fullscreen mode Exit fullscreen mode

In the example above, the customReverse method reverses in place the array and returns it.

Custom forEach

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

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

output.customForEach(elem => {
    console.log(elem);
}); // 1 2 3 4 5 6 7 8 9 10
Enter fullscreen mode Exit fullscreen mode

In the example above, the customForEach method takes as a parameter a callback function and it is applied on every element in the array. Also, the callback function receives additional the index and the array itself in case that will be used.

Custom map

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

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

output = output.customMap(elem => {
    return 3*elem;
});

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

In the example above, the customMap method takes as a parameter a callback function and for each element in the array we apply the callback function and we return the result in a new array. Again, the callback function receives additional the index and the array itself in case that will be used.

Custom filter

Array.prototype.customFilter = 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 output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

output = output.customFilter((elem) => {
    return elem % 2 === 0;
});

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

In the example above, the customFilter method takes as a parameter a callback function and for each element in the array we apply the callback function and for the values that pass the callback function we return the result in a new array.

Custom reduce

Array.prototype.customReduce = function (callback, initialValue) {
    let value = initialValue;

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

    return value;
}

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

const sum = output.customReduce((acc = 0, elem) => {
    return acc + elem;
});

console.log(sum); // 55
Enter fullscreen mode Exit fullscreen mode

In the example above, the customReduce method takes as parameters a callback function and an accumulator variable and we apply the callback function against the accumulator for each element in the array until to reduce it to a single value.

You can check my github repository here.

Resources

đź’– đź’Ş đź™… đźš©
zagaris
Aris Zagakos

Posted on December 5, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related