One of the most complex array method is array.reduce
. So in this article we will learn about the reduce function while making its polyfill.(A polyfill is a piece of code used to provide modern functionality on older browsers that do not natively support it).
Okay let's start from the beginning. The reduce
function takes a callback function. So the way we would use it is:
let arr = [1, 2, 3, 4, 5]
arr.reduce(function(){
console.log("hello")
})
Now if we run this you will see
hello was printed on console 4 time. But notice that our array has 5 elements. So the reduce function will be called array.length - 1
times. So we can easily mimic this behaviour by using a simple for loop.
function myReduce(arr, cb){
for(let i = 0; i < arr.length - 1; i++){
cb()
}
}
let arr = [1, 2, 3, 4, 5]
myReduce(arr, function(){
console.log("hello")
})
If you run this code you will see the output is the same. But this is not that useful. So lets move on.
When the reduce
function calls the callback function it also passes some arguments to it. Lets console.log
the first two arguments it receive.
let arr = [1, 2, 3, 4, 5]
arr.reduce(function(a, b){
console.log(a, b)
})
The output looks really weird. At first the value of a was the first element in array and value of b was the second element of our array. After that in next function calls the value of a was undefined
and the value of b was the next elements in our array. What's happening? Let's try to return something in our callback function.
let arr = [1, 2, 3, 4, 5]
arr.reduce(function(a, b){
console.log(a, b)
return "hello"
})
Okay it looks like initially the value of a is the first element of our array after that what ever we return from our callback function the value of a will become that. So lets do that in our custom function.
function myReduce(arr, cb){
let a = arr[0]
for(let i = 0; i < arr.length - 1; i++){
//setting the value of a to what ever the call back returns
a = cb(a, arr[i])
}
}
let arr = [1, 2, 3, 4, 5]
myReduce(arr, function(a, b){
console.log(a, b)
return "hello"
})
Seems like our output is a little different. To fix that instead of saying for(let i = 0; i < arr.length - 1; i++)
we can say for(let i = 1; i < arr.length; i++)
function myReduce(arr, cb){
let a = arr[0]
for(let i = 1; i < arr.length; i++){
//setting the value of a to what ever the call back returns
a = cb(a, arr[i])
}
}
let arr = [1, 2, 3, 4, 5]
myReduce([1, 2, 3, 4, 5], function(a, b){
console.log(a, b)
return "hello"
})
And now our outputs are the same.
The reduce
function can also take a second argument. So let's see what happens if we pass a second argument.
let arr = [1, 2, 3, 4, 5]
arr.reduce(function(a, b){
console.log(a, b)
return "hello"
}, "Hi") //passing hi as second argument
So it looks like if we pass a second value to out reduce
function the initial value of a will be what we pass after that it will be what we return from the callback function. And the value of b will starts from the first element of our array. Well then, lets add this logic to our custom JS function as well.
function myReduce(arr, cb, initialVal){
let a = arr[0]
let startIdx = 1
if(initialVal){
a = initialVal
startIdx = 0
}
for(let i = startIdx; i < arr.length; i++){
//setting the value of a to what ever the call back returns
a = cb(a, arr[i])
}
}
let arr = [1, 2, 3, 4, 5]
myReduce(arr, function(a, b){
console.log(a, b)
return "hello"
}, "Hi")
Okay we are doing progress. Now our array reduce function also returns something. lets console.log
it.
let arr = [1, 2, 3, 4, 5]
let res = arr.reduce(function(a, b){
console.log(a, b)
return "hello"
}, 0)
console.log("res: " + res)
it looks like it also returns hello. Okay let's try to return something new from the callback function. We can return a + b
. So each time the callback function is called the value of b will be added to a
let arr = [1, 2, 3, 4, 5]
let res = arr.reduce(function(a, b){
console.log(a, b)
return a + b
}, 0)
console.log("res: " + res)
Here we can see after the last callback function call value of a was 10 and b was 5. so the callback function returned 10 + 5
which means the final value of a will be
10 + 5
or 15
and our reduce function is also returning 15
. So the reduce function will return the final value of a.
Now lets make our custom function do that as well
function myReduce(arr, cb, initialVal){
let a = arr[0]
let startIdx = 1
if(initialVal){
a = initialVal
startIdx = 0
}
for(let i = startIdx; i < arr.length; i++){
//setting the value of a to what ever the call back returns
a = cb(a, arr[i])
}
return a //returning the final value of a
}
let arr = [1, 2, 3, 4, 5]
let res = myReduce(arr, function(a, b){
console.log(a, b)
return a + b
}, 0)
console.log("res: " + res)
Almost there. Now instead of having to say let res = myReduce(arr, ...)
I should be able to say arr.myReduce
. To do so we need to add myReduce
to array
s prototype.
Array.prototype.myReduce = function(cb, initialVal){
let arr = this //'this' is the array on which this function was called
let a = arr[0]
let startIdx = 1
if(initialVal){
a = initialVal
startIdx = 0
}
for(let i = startIdx; i < arr.length; i++){
//setting the value of a to what ever the call back returns
a = cb(a, arr[i])
}
return a //returning the final value of a
}
let arr = [1, 2, 3, 4, 5]
let res = arr.myReduce(function(a, b){
console.log(a, b)
return a + b
}, 0)
console.log("res: " + res)
And there you go. Now you not only know how the reduce
function works, you have created your own reduce function from scratch. Now to polish your skills you can check this link
and these examples
-
Getting the sum of array
let arr = [1, 2, 3, 4, 5] let sum = arr.reduce(function(a, b){ return a + b }) //or using arrow function let sum = arr.reduce((a, b) => a + b) console.log(sum) //output: 15
Remove duplicates from array
let arr = [1, 2, 2, 3, 4, 4, 5]
let newArr = arr.reduce((a, b) => {
if(a.indexOf(b) == -1) a.push(b)
return a
}, [])
console.log(newArr) //output: [1, 2, 3, 4, 5]
- Find the largest number in array
let arr = [2, 5, 345, 32, 52]
let max = arr.reduce((a, b) => {
if(b > a) a = b
return a
})
console.log(max) //output: 345
That's all for now. Make sure to out check out my other articles.