loading...
Cover image for Understanding reduce in JavaScript

Understanding reduce in JavaScript

dhanushadithya profile image Dhanush Adithya ・3 min read

Let me be honest, it took me a while to understand the Higher-Order Function - reduce. In my opinion, I think many faced this situation or facing it. So, let's get started with some theoretical explanation and we hop into some code.

What is reduce ?

  • It's a Higher-Order Function
  • It takes 2 arguments
    • first argument is a function which takes 4 arguments
    • second argument is the initial value
  • It's one of the methods of Array
  • It won't modify the original array

What does that 4 parameters and intialValue do ?

Array.reduce(function (accumulator, value, index, array) {
    return /* modified accumulator or just the accumulator */
}, initialValue)
Enter fullscreen mode Exit fullscreen mode

Nice, now what do those parameters do? Okay,

Parameter Description
initialValue The value of the accumulator in the first invocation of the function (1st argument).
Hence the name initialValue.
accumulator This will be the return value of each invocation of the function.
It should be the same type of the initialValue on each and every invocation.
value The value of the array element.
index The index of the array element. (Optional)
array The array itself. (Optional)

Enough Explaining. Show me the code!

// The common example of reduce method
function sum(acc, val) {
    // the optional parameters are omitted
    return acc + val
}
const arr = [1, 2, 3, 4]
const sumOfArr = arr.reduce(sum, 0) // = 10
// Here the initialValue's type is number 
// so the type of `sumOfArr` will be the same (number)
Enter fullscreen mode Exit fullscreen mode

What's happening here? Let's see with this table,

Invocation accumulator value return
First 0 (initialValue) arr[0] = 1 0 + 1 = 1
Second 1 arr[1] = 2 1 + 2 = 3
Third 3 arr[2] = 3 3 + 3 = 6
Fourth 6 arr[3] = 4 6 + 4 = 10

So the result would be the sum of the used array (here arr).

// The optional parameters are omitted for this ex. too
// and I'm gonna use arrow functions
const rick = ['never', 'gonna', 'give', 'you', 'up', 'never', 'gonna', 'let', 'you', 'down']
const ricksObj = rick.reduce((acc, val) => {
    acc[val] = (acc[val] + 1) || 1
    return acc
}, {})
// { never: 2, gonna: 2, give: 1, you: 2, up: 1, let: 1, down: 1 }
Enter fullscreen mode Exit fullscreen mode

The ricksObj is a object as initialValue = {}. So here, what the does is super simple. It returns an object with properties of rick array elements and values as the occurrence of each element in the array. Let's create a table.

Invocation accumulator value return
First {} (initialValue) 'never' acc['never'] is undefined.
So, acc['never'] = 1.
{ never: 1 }
Second { never: 1 } 'gonna' Same as above.
{ never: 1, gonna: 1 }

On third, fourth and fifth invocation, the array elements are unique so, they all get the value of 1 as per the expression (acc[val] + 1) || 1.

Invocation accumulator value return
Sixth { never: 1, gonna: 1, give: 1, you: 1, up: 1 } 'never' As the property never is no more undefined, the property's value get incremented.
{ never: 2, gonna: 1, give: 1, you: 1, up: 1 }

and so on.

What else does this method do !?

Let's use an API and use reduce with the response Array.

fetch('https://arrowverse-api.vercel.app/api/characters?page=1&limit=10')
  .then(res => res.json())
  .then(data => {
    // ----------------------------------------------------
    data = data.reduce((acc, val) => {
      if(val.imgUrl !== '') {
        acc.push({ name: val.name, imgUrl: val.imgUrl })
        return acc
      } else {
        return acc
      }
    }, [])
    console.log(data)
    // -----------------------------------------------------
  }
)
Enter fullscreen mode Exit fullscreen mode

There are many properties in the objects inside the array but I need only the name of the character and the image URL, but some characters don't have the image URL, so I need to exclude them. The exact same result is acquired when you use map and filter, like this

fetch('https://arrowverse-api.vercel.app/api/characters?page=1&limit=10')
  .then(res => res.json())
  .then(data => {
    // ----------------------------------------------------
    data = data
        .map(val => ({
            name: val.name,
            imgUrl: val.imgUrl
        }))
        .filter(data => data.imgUrl !== '')
    console.log(data)
    // -----------------------------------------------------
  }
)
Enter fullscreen mode Exit fullscreen mode

So both of them work. I personally like to use reduce as it's so compact and powerful. Try the blocks of code in the browser console

I hope you find this article helpful.

Discussion

pic
Editor guide