Understanding array.reduce by creating its polyfill

Shuvo - Oct 23 '21 - - Dev Community

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")
})
Enter fullscreen mode Exit fullscreen mode

Now if we run this you will see
basic array reduce call
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")
})
Enter fullscreen mode Exit fullscreen mode

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)
})
Enter fullscreen mode Exit fullscreen mode

printing value received from reduce
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"
})
Enter fullscreen mode Exit fullscreen mode

returning value in reduce cb
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"
})
Enter fullscreen mode Exit fullscreen mode

returning value in myReduce cb
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"
})
Enter fullscreen mode Exit fullscreen mode

returning value in myReduce cb
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
Enter fullscreen mode Exit fullscreen mode

second value passed in array reduce
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")
Enter fullscreen mode Exit fullscreen mode

custom array reduce demo

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)
Enter fullscreen mode Exit fullscreen mode

array reduce demo
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)
Enter fullscreen mode Exit fullscreen mode

array reduce demo

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)
Enter fullscreen mode Exit fullscreen mode

custom array reduce demo
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 arrays 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)
Enter fullscreen mode Exit fullscreen mode

final demo
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

  1. 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
    
  2. 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]
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode

That's all for now. Make sure to out check out my other articles.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .