Implement JavaScript Array Methods From Scratch
Tags: javascript, webdev, beginners
Published: 2021-12-05 00:24:06


## Table of Contents
1. [Introduction](#introduction)
2. [prototype](#what-is-prototype)
3. [this](#what-is-this)
4. [Array Methods](#lets-implement-the-array-methods)
5. [Resources](#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 <u>don't intend to replace the existing methods</u> but to provide a better understanding of how these methods work and their uses.


| Methods     | Description |
| ----------- |  -----------|
| [indexOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)   |Returns the first index at which a given element can be found in the array, otherwise returns -1.        |
|[lastIndexOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf)|Returns the last index at which a given element can be found in the array, otherwise returns -1.
| [reverse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) | Returns the reversed array.
| [forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)   |Executes a provided function once for each array element.|
| [map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)            |Creates a new array with the results of calling a provided function on every element in the calling array.|
| [filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)    | Creates a new array with all elements that pass the test implemented by the provided function.|
| [reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/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](https://dev.to/zagaris/understanding-map-filter-and-reduce-in-javascript-293i).

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.


```javascript
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

```
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).

```javascript
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] }
```

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**_

```javascript
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
```
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**_

```javascript
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
```
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**_

```javascript
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]
```
In the example above, the `customReverse` method reverses in place the array and returns it.


_**Custom forEach**_

```javascript
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
```
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**_

```javascript
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]
```
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**_

```JavaScript
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 ]
```
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**_

```JavaScript
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
```
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](https://github.com/zagaris/Array-Methods-JavaScript).


## Resources

* [MDN: JavaScript Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
* [MDN: Prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes)
* [MDN: This - JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)