Understanding reduce in JavaScript
Tags: javascript, array, reduce, method
Published: 2020-10-19 10:36:39

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 ?

```js
Array.reduce(function (accumulator, value, index, array) {
    return /* modified accumulator or just the accumulator */
}, initialValue)
```

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).<br />Hence the name _initialValue_. |
| accumulator  | This will be the return value of each invocation of the function.<br />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!

```js
// 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)
```

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`).

```js
// 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 }
```

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.<br />So, acc['never'] = 1.<br />`{ never: 1 }` |
| Second     | `{ never: 1 }`      | 'gonna' | Same as above.<br />`{ 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.<br />`{ 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.

```js
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)
    // -----------------------------------------------------
  }
)
```

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

```js
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)
    // -----------------------------------------------------
  }
)
```

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.