Hello Everyone,
Today let's implement our own version of the map() and reduce() array methods in JavaScript.
The actual implementation of the inbuilt array methods are way more complex than this. What we are aiming towards is to understand the Array methods better.
myMap()
First let's understand what does the built in map method do.
- Takes an array as input -> returns an array as output.
- Iterates over all the elements of array.
- Returns an array of same length as the original array.
- Does not mutate the original array.
Here is our implementation of the map() Array method.
const numArr = [1, 2, 3, 4];
function myCustomMap(callback) {
const newArr = [];
for(let i = 0; i < this.length; i++) {
newArr.push(callback(this[i], i, this));
}
return newArr;
}
Array.prototype.myMap = myCustomMap;
numArr.map(elm => elm * 2); // [2, 4, 6, 8]
numArr.myMap(elm => elm * 2); // [2, 4, 6, 8]
Let's see what's going on in the above snippet.
- myCutomMap function takes a callback (this callback is the function we write in map).
- We loop over all elements of array.
- The callback function is called with the current element and the returned value is pushed in the newArr.
- newArr is returned from the myCustomMap function.
- We add the myCustomMap function in Array.prototype, so that we can use it with dot notation.
- The "this" keyword in myCustomMap refers to the array on which the myCustomMap is used with dot notation. (numArr.myMap((elm) => elm * 2) // here "this" refers to numArr).
And, that's how you build your own custom map() Array method.
myReduce()
Now let's understand what does the built in reduce method do.
- Takes an array -> Returns any type of data you want.
- Iterates over all the elements of the array.
- Reduces the array to any datatype you want.
- Does not mutate the original array.
const personArray = [{name: "Swastik", age: 23}, {name: "John", age: 42}, {name: "Rock", age: 45}];
function myCustomReduce(callback, initialValue) {
for(let i = 0; i < this.length; i++) {
initialValue = callback(initialValue, this[i], i, this);
}
return initialValue;
}
Array.prototype.myReduce = myCustomReduce;
personArray.reduce((acc, cv) => {
acc = {
...acc,
[cv.name]: cv.name.length,
};
return acc;
}, {}); // {Swastik: 7, John: 4, Rock: 4}
personArr.myReduce((acc, cv) => {
acc = {
...acc,
[cv.name]: cv.name.length,
};
return acc;
}, {}); // {Swastik: 7, John: 4, Rock: 4}
Now let's see what's going on in the myCustomReduce snippet.
We want to reduce the following array
[{name: "Swastik", age: 23}, {name: "John", age: 42}, {name: "Rock", age: 45}]
to and object with key as name and value as length of the name
{Swastik: 7, John: 4, Rock: 4}
Steps:
- myCutomReduce function takes a callback and an initialValue (this initialValue is the datatype which we want the reduce to return).
- We loop over all elements of array.
- The callback function is called with the current element and the returned value is assigned to the initialValue. With every iteration initialValue is updated.
- initialValue is returned from the myCustomReduce function.
- We add the myCustomReduce function in Array.prototype, so that we can use it with dot notation.
- The "this" keyword in myCustomReduce refers to the array on which the myCustomReduce is used with dot notation.
And, tha't how you build your own version of the reduce Array method in JavaScript.
I had a great time writing and recording about this topic, I hope you felt the same while reading and watching this.
I also run a weekly newsletter, so you can join me there also: https://swastikyadav.com
Thank You!
Top comments (4)
Why the in-between variable? You could just write the function as
(acc, cv) => {...acc, [cv.name]: cv.name.length}
Or, if you don't mind the in-between variable, at least make better use of it and mutate the old object instead of copying it entirely
In btwn variable is to keep things as soon so simple as possible because this is a blog post.
But yes, nice enhancement. Thanks for sharing.
For me the canonical way of learning about map and reduce is to
foldl
(reduce) using recursionmap
in terms offoldl
Now in JavaScript this isn't terribly efficient …
This transpiles down to
initialValue
should be optional