How to implement every JavaScript array method

To use a method on a given array, we type [].methodName. They are all defined in the Array.prototype object. Here, however, we won’t be using these; instead, we’ll define our own versions starting from the simple method and build up on top of these until we get them all.

There is no better way to learn than to take things apart and put them back together. Note that when working on our implementations, we won’t be overriding existing methods, since that is never a good idea (some packages we import may be dependent on it). Also, this is going to allow us to compare how our versions fare against the original methods.

So instead of writing this:

We are going to do this:

We could also implement our methods by using the class keyword and extending the Array constructor like so:

The only difference would be that instead of using the array argument, we would be using the this keyword.

However, I felt this would bring about unnecessary confusion, so we are going to stick with the first approach.

With that out of the way, let’s kick it off by implementing the easiest one — the forEach method!

Iterating over collections


The Array.prototype.forEach method takes a callback function and executes it for each item in the array without mutating the array in any way.


We iterate over the array and execute the callback for each element. The important thing to note here is that the method doesn’t return anything — so, in a way, it returns undefined.

Method chaining

What’s great about working with array methods is the possibility of chaining operations together. Consider the following code:

This way, we don’t have to save the result of map to a variable and generally have better-looking code as a result.

Unfortunately, forEach doesn’t return the input array! This means we can’t to do the following:

The console.log here, of course, is useless.

A logging utility function

I have written a simple utility function that will better explain what each method does: what it takes as input, what it returns, and whether or not it mutates the array.

Here’s the utility function run for our implementation of forEach:

Due to the fact that we implement the methods as functions, we have to use the following syntax: forEach(array, ...) instead of array.forEach(...).

Note: I have also created test cases for every method to be sure they work as expected — you can find them in the repository.


One of the most commonly used methods is It lets us create a new array by converting the existing values into new ones.


The callback provided to the method takes the old value as an argument and returns a new value, which is then saved under the same index in the new array, here called result.

It is important to note here that we return a new array; we don’t modify the old one. This is an important distinction to make due to arrays and objects being passed as references here. If you are confused by the whole references versus values thing, here’s a great read.


Another very useful method is Array.prototype.filter. As the name suggests, it filters out the values for which the callback returned is false. Each value is saved in a new array that is later returned.


We take each value and check whether the provided callback has returned true or false and either append the value to the newly created array or discard it, appropriately.

Note that here we use the push method on the result array instead of saving the value at the same index it was placed in the input array. This way, result won’t have empty slots because of the discarded values.


The reduce method is, admittedly, one of the more complicated methods. The extensiveness of its use, however, cannot be overstated, and so it is crucial to get a good grasp on how it works. It takes an array and spits out a single value. In a sense, it reduces the array down to that very value.

How that value is computed, exactly, is what needs to be specified in the callback. Let’s consider an example — the simplest use of reduce, i.e., summing an array of numbers:

Note how the callback here takes two arguments: sum and number. The first one is always the result returned by the previous iteration, and the second one is the element of the array we’re currently considering in the loop.

And so here, as we iterate over the array, sum is going to contain the sum of numbers up to the current index of the loop since with each iteration we just add to it the current value of the array.


We create two variables, acc and startAtIndex, and initialize them with their default values, which are the argument initValue and 0, respectively.

Then, we check whether or not initValue is undefined. If it is, we have to set as the initial value the first value of the array and, so as not to count the initial element twice, set the startAtIndex to 1.

Each iteration, the reduce method saves the result of the callback in the accumulator (acc), which is then available in the next iteration. For the first iteration, the accumulator is set to either the initValue or array[0].


What operation on arrays can be more common than searching for some specific value? Here are a few methods to help us with this.


As the name suggests, findIndex helps us find the index of a given value inside the array.

The method executes the provided callback for each item in the array until the callback returns true. The method then returns the current index. Should no value be found, -1 is returned.



find only differs from findIndex in that it returns the actual value instead of its index. In our implementation, we can reuse the already-implemented findIndex.



indexOf is another method for getting an index of a given value. This time, however, we pass the actual value as an argument instead of a function. Again, to simplify the implementation, we can use the previously implemented findIndex!


We provide an appropriate callback to findIndex, based on the value we are searching for.


lastIndexOf works the same way as indexOf, only it starts at the end of an array. We also (like indexOf) pass the value we are looking for as an argument instead of a callback.


We do the same thing we did for findIndex, but instead of executing a callback, we compare value and searchedValue. Should the comparison yield true, we return the index; if we don’t find the value, we return -1.


The includes method works like the some method, but instead of a callback, we provide as an argument a value to compare elements to.



Sometimes our arrays become two or three levels deep and we would like to flatten them, i.e., reduce the degree to which they are nested. For example, say we’d like to bring all values to the top level. To our aid come two new additions to the language: the flat and flatMap methods.


The flat method reduces the depth of the nesting by pulling the values out of the nested array.

Since the level we provided as an argument is 1, only the first level of arrays is flattened; the rest stay the same.


First, we check whether or not the depth argument is lower than 1. If it is, it means there is nothing to flatten, and we should simply return the array.

Second, we check whether the array argument is actually of the type Array, because if it isn’t, then the notion of flattening is meaningless, so we simply return this argument instead.

We make use of the reduce function, which we have implemented before. We start with an empty array and then take each value of the array and flatten it.

Note that we call the flat function with (depth - 1). With each call, we decrement the depth argument as to not cause an infinite loop. Once the flattening is done, we append the returned value to the result array.

Note: the concat function is used here to merge two arrays together. The implementation of the function is explained below.


flatMap, as the name might suggest, is a combination of flat and map. First we map according to the callback and later flatten the result.

In the map method above, for each value, we returned precisely one value. This way, an array with three items still had three items after the mapping. With flatMap, inside the provided callback we can return an array, which is later flattened.

Each returned array gets flattened, and instead of getting an array with three arrays nested inside, we get one array with nine items.


As per the explanation above, we first use map and then flatten the resulting array of arrays by one level.

Joining, appending, and reversing arrays


As you’ve just seen, the concat method is very useful for merging two or more arrays together. It is widely used because it doesn’t mutate the arrays; instead, it returns a new one that all the provided arrays are merged into.


concat takes an array as the first argument and an unspecified number of values that could be arrays (but also could be anything else — say, primitive values) as the second argument.

At first, we create the result array by copying the provided array (using the spread operator, which spreads the provided array’s values into a new array). Then, as we iterate over the rest of the values provided, we check whether the value is an array or not. If it is, we use the push function to append its values to the result array.

If we did push(result, value), we would only append the array as one element. Instead, by using the spread operator push(result, ...value), we are appending all the values of the array to the result array. In a way, we flatten the array one level deep!

Otherwise, if the current value is not an array, we also push the value to the result array — this time, of course, without the spread operator.


The join method turns an array into a string, separating the values with a string of choice.


We make use of the reduce function: we pass to it the provided array and set the initial value to an empty string. Pretty straightforward so far.

The callback of reduce is where the magic happens: reduce iterates over the provided array and pieces together the resulting string, placing the desired separator (passed as joinWith) in between the values of the array.

The array[0] value requires some special treatment, since at that point result is still undefined (it’s an empty string), and we don’t want the separator (joinWith) in front of the first element, either.


The reverse method reverses the order of values in an array.


The idea is simple: first, we define an empty array and save the last index of the one provided as an argument. We iterate over the provided array in reverse, saving each value at (lastIndex - index) place in the result array, which we return afterwards.

Adding, removing, and appending values


The shift method shifts the values of an array down by one index and by doing so removes the first value, which is then returned.


We start by saving the provided array’s original length and its initial value (the one we’ll drop when we shift everything by one). We then iterate over the array and move each value down by one index. Once done, we update the length of the array and return the once-initial value.


The unshift method adds one or more values to the beginning of an array and returns that array’s length.


We start by concatenating values (individual values passed as arguments) and array (the array we want to unshift). It is important to note here that values come first; they are to be placed in front of the original array.

We then save the length of this new array and iterate over it, saving its values in the original array and overwriting what was there to begin with.


Taking out a single value out of an array is simple: we just refer to it using its index. Sometimes, however, we would like to take a bigger slice of an array — say, three or four elements at once. That’s when the slice method comes in handy.

We specify the start and the end indices, and slice hands us the array cut from the original array at these indices. Note, however, that the end index argument is not inclusive; in the following example, only elements of indices 3, 4, and 5 make it to the resulting array.


We iterate over the array from startIndex to endIndex and push each value to the result. We also make use of the default parameters here so that the slice method simply creates a copy of the array when no arguments are passed. We achieve this by setting by default startIndex to 0 and endIndex to the array’s length.

Note: the if statement makes sure we push only if the value under a given index exists in the original array.


The splice method simultaneously removes a given number of values from the array and inserts in their place some other values. Although not obvious at first, we can add more values than we remove and vice versa.

First, we specify the starting index, then how many values we would like to remove, and the rest of the arguments are the values to be inserted.


The idea is to make two cuts at insertAtIndex and insertAtIndex + removeNumberOfElements. This way, we slice the original array into three pieces. The first piece (firstPart) as well as the third one (here called secondPart) are what will make it into the resulting array.

It is between these two that we will insert the values we passed as arguments. We do this with the concat method. The remaining middle part is removedElements, which we return in the end.


The push method lets us append values at the end of an array.


First we save the length of the original array and how many values to append there are in their respective variables. We then iterate over the provided values and append them to the original array.

We start the loop at index = 0, so each iteration we add to index the array’s length. This way we don’t overwrite any values in the original array, but actually append them.


Using the array’s methods efficiently is the basis for becoming a good developer. Acquainting yourself with the intricacies of their inner workings is the best way I know to get good at it.

Note: I didn’t cover sort and toLocaleString here because their implementations are overly complicated and, for my taste, too convoluted for beginners. I also didn’t discuss copyWithin, since it’s never used — it’s absolutely useless.

Thanks for reading…😊
You can also visit my Linkedin profile…

Angular Developer, UI/UX Designer