JavaScript includes several functions for working with arrays that go beyond the for
loop. You may have used these functions in your own projects and wondered how they work and why you’d use one over another.
A great way to understand how something works is to build your own version from scratch. In this article, you are going to do that by creating your own versions of map
, filter
, sort
, and reduce
from scratch. When you’re done, you’ll have a better understanding of these functions and their uses.
By combining ES6 Arrow Functions with JavaScript Array functions, you can write extremely powerful and clean code.
Let’s start with an example. Let’s say you want to iterate through an array of numbers, increment each element by one, and return the new array. In the past, you would need to do several things to accomplish this:
The code would look like this:
const arr = [1, 2, 3];
const newArray = [];
for (let i = 0; i < arr.length; i++) {
newArray[i] = arr[i] + 1;
}
return newArray;
But with the built-in map
function, you can accomplish this in a single line of code:
return arr.map(element => ++element);
JavaScript Array methods heavily leverage ES6 Arrow Functions.
Each of the Array functions we will cover accept a function as a parameter. They will iterate through each element of the array and call that function to determine what to do with each element. After iterating through each element and calling the callback function, a new array or item will be returned.
To follow this tutorial locally, you will need an editor (such as Visual Studio Code) and a sandbox environment extension (such as Quokka.js).
To follow the tutorial online, you can use CodePen or CodeSandbox.
map
iterates through each element, transforms it in some way, adds it to a new array, and returns the new array.
Warning: In this article, you’re going to extend JavaScript global objects with custom functions. This is for educational purposes only, as this practice has the potential to introduce side effects in production code.
JavaScript array functions are part of the Array prototype, similar to functions on a class in Java, for example. To override them, you can assign a new function to Array.prototype
.
Let’s create a new function and assign it to Array.prototype.mapFromScratch
:
const myCustomMapFunction = function(callback) {
console.log('My Custom Map Function!');
}
Array.prototype.mapFromScratch = myCustomMapFunction;
const arr = [1, 2, 3];
arr.mapFromScratch();
If you run this code, you will see the log message in the console:
OutputMy Custom Map Function!
Now, add the for
loop and print out each element. Due to the array itself calling the method, you get access to that array by referencing this
:
const myCustomMapFunction = function(callback) {
console.log('My Custom Map Function!');
// 'this' refers to the array
for (let i = 0; i < this.length; i++) {
console.log(this[i]);
}
}
Now, perform any required transformation by calling the callback function. When you do, you will pass it the current element and the current index:
const myCustomMapFunction = function(callback) {
console.log('My Custom Map Function!');
// 'this' refers to the array
for (let i = 0; i < this.length; i++) {
const transformedElement = callback([this[i], i);
}
}
Finally, add the transformed elements to a new array and return that array.
const myCustomMapFunction = function(callback) {
console.log('My Custom Map Function!');
const newArray = [];
// 'this' refers to the array
for (let i = 0; i < this.length; i++) {
newArray[i] = callback(this[i], i);
}
return newArray;
}
Let’s take a look of your rewritten function in action by testing it with a function that will increment each value in the array:
// arr = [1, 2, 3]
// expected = [2, 3, 4]
console.log(arr.mapFromScratch((element) => ++element));
You will receive the following output:
OutputMy Custom Map Function!
[2, 3, 4]
In this step you implemented a custom map
function. Next, let’s explore implementing a filter
function.
The filter
function returns a new array of elements filtered from the original array.
Let’s create a new function and assign it to Array.prototype.filterFromScratch
:
const myCustomFilterFunction = function(callback) {
console.log('My Custom Filter Function!');
}
Array.prototype.filterFromScratch = myCustomFilterFunction;
const arr = [1, 2, 3];
arr.filterFromScratch();
Now, set up the for
loop to iterate through each element:
const myCustomFilterFunction = function(callback) {
console.log('My Custom Filter Function!');
const newArray = [];
for (let i = 0; i < this.length; i++) {
console.log(this[i]);
}
}
Inside of the for
loop, you need to decided whether or not to add each element to the new array. This is the purpose of the callback function, so you use it to conditionally add each element. If the return value is true
, push the element on to the return array:
const myCustomFilterFunction = function(callback) {
console.log('My Custom Filter Function!');
const newArray = [];
for (let i = 0; i < this.length; i++) {
if (callback(this[i])) {
newArray.push(this[i]);
}
}
return newArray;
}
Let’s take a look at your rewritten function in action by testing it with a function that will display values that are greater than 1
:
// arr = [1, 2, 3]
// expected = [2, 3]
console.log(arr.filterFromScratch((element) => element > 1));
You will receive the following output:
OutputMy Custom Filter Function!
[2, 3]
With that, you have implemented a custom filter
function. Next you will work with the sort
function.
The sort
function returns a sorted array from the original array.
Let’s create a new function and assign it to Array.prototype.sortFromScratch
:
const myCustomSortFunction = function(callback) {
console.log('My Custom Sort Function!');
}
Array.prototype.sortFromScratch = myCustomSortFunction;
const arr = [3, 2, 1];
arr.sortFromScratch();
We are going to be using Bubble Sort for this sort implementation. Here’s the approach we will take:
With Bubble Sort, you have to iterate through the array fully once for each element in the array. This calls for a nested for
loop where the inner loop iterates through stopping one short of the final element, so let’s add that now.
Note: This is intended for educational purposes and isn’t an efficient method for sorting.
const myCustomSortFunction = function(callback) {
console.log('My Custom Sort Function!');
const newArray = [];
for (let i = 0; i < newArray.length; i++) {
for (let j = 0; j < newArray.length - 1; j++) {
}
}
}
You also don’t want to alter the original array. To avoid this, you can copy the original array into the new array using the Spread Operator.
const myCustomSortFunction = function(callback) {
console.log('My Custom Sort Function!');
const newArray = [...this];
for (let i = 0; i < newArray.length; i++) {
for (let j = 0; j < newArray.length - 1; j++) {
}
}
}
The callback function takes two parameters, the current element and the next element, and will return whether or not they are in order. In our case, if the callback function returns a number greater than 0
, we want to swap the two elements.
const myCustomSortFunction = function(callback) {
console.log('My Custom Sort Function!');
const newArray = [...this];
for (let i = 0; i < newArray.length; i++) {
for (let j = 0; j < newArray.length - 1; j++) {
if (callback(newArray[j], newArray[j + 1]) > 0) {
// swap the elements
}
}
}
}
To swap the elements, you make a copy of one, replace the first one, and then replace the second one with the copy. When finished, it returns the newly sorted array.
const myCustomSortFunction = function(callback) {
console.log('My Custom Sort Function!');
const newArray = [...this];
for (let i = 0; i < newArray.length; i++){
for (let j = 0; j < newArray.length - 1; j++) {
if (callback(newArray[j], newArray[j + 1]) > 0) {
const temp = newArray[j + 1];
newArray[j + 1] = newArray[j];
newArray[j] = temp;
}
}
}
// array is sorted
return newArray;
}
Let’s take a look of your rewritten function in action by testing it with a function that quicksorts from low to high:
// arr = [3, 2, 1]
// expected = [1, 2, 3]
console.log(arr.sortFromScratch((current, next) => current - next));
You will receive the following output:
OutputMy Custom Sort Function!
[1, 2, 3]
Now that you’ve created a custom sort
function, you’re ready to move on to implementing a reduce
function.
The reduce
function iterates through each element and returns one single value.
reduce
does not return a new array like the other functions. It actually “reduces” the elements in an array to one final value: a number, a string, or an object. One of the most common reasons for using reduce
is for when you want to sum up all the elements in an array of numbers.
Let’s create a new function and assign it to Array.prototype.reduceFromScratch
:
const myCustomReduceFunction = function(callback) {
console.log('My Custom Reduce Function!');
}
Array.prototype.reduceFromScratch = myCustomReduceFunction;
const arr = [1, 2, 3];
arr.reduceFromScratch();
For reduce
to return one final value, it needs a starting value to work with. The callback function that the user passes along will determine how to update this accumulator based on each element of the array and return it at the end. The callback function must return the updated accumulator.
Add your for
loop now, and make a call to the callback function. The return value becomes the new accumulator. After the loop ends, you return the accumulator.
const myCustomReduceFunction = function(callback, accumulator) {
console.log('My Custom Reduce Function!');
for (let i = 0; i < this.length; i++) {
accumulator = callback(accumulator, this[i]);
}
return accumulator;
}
Let’s take a look of your rewritten function in action by testing it with a function that sums up the contents of an array:
// arr = [1, 2, 3]
// expected = 6
console.log(arr.reduceFromScratch((accumulator, element) => accumulator + element, 0));
OutputMy Custom Reduce Function!
6
JavaScript’s array functions are extremely useful. In this tutorial, you reimplemented the array functions to get a better understanding of how they work so you can use them more effectively.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!