# JavaScript Array Methods         Detailed Review of forEach() ,map , filter() and reduce()

# Let’s first understand 🤔 What is an Array?

Quoting from MDN directly.

> The `Array` object, as with arrays in other programming languages, enables storing a collection of multiple items under a single variable name and has members for performing common array operations.
> 

For example see this sample of code of JS

```jsx
// 'kings' array created using array literal notation.
const kings = ['Ashoka', 'Samundragupta'];
console.log(kings.length);
// 2
```

# Which specific Array Methods will we learn about?

- **forEach() method**
- **map**
- **filter**
- **reduce**

# `forEach()` Method 😍

If `for` loop is a jack of all trades in looping over an array. And you hate having to iterate using index wishing if only there were easier ways.

`forEach()` is for the answer for you, it is a master of simplicity and easily understood code.

## Syntax 😌

### This is the syntax for using `forEach()` using arrow function.

```jsx
forEach((element, index, array) => { /* ... */ })
```

### Let’s understand the parameters in the syntax

- `callbackFn` : Function which executes on each element
- `element` : Current element being worked on in array.
- `index` (Optional) : The index of element in array
- `array` (Optional) : Array upon which `forEach()` was called .

### Example Usage for looping over an array.

```jsx
const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]

arr.forEach(element => console.log(element));
// 
//   { name: 'Aashirwad', roll: 4 },
//   { name: 'Pankaj', roll: 78 },
//   { name: 'Ayush', roll: 70 },
//   { name: 'Nisha', roll: 33 }
//
```

## Pros of `forEach()` 😏

- Increases readability of Code eliminating the possibility of bugs
- It is convenient because there is no need to dereference inside of the loop. So the risk of overrunning or underrunning is eliminated.

## Cons of `forEach()` 🥲

- Can’t skip an item .i.e the array index counter will always increase by +1.
- No reverse order traversals.
- It does not mutate the array it is called on however `callbackFn` could.
- It always returns the value undefined hence is not chainable.
- There is no way to stop or break a `forEach()` loop ( like using break or return in for loop)

## Gotchas! 😳

<aside>
💡 It expects a synchronous function. It does not wait for promises .

</aside>

```jsx
const wars = [2, 8, 5];
let sum = 0;

const sumWarFunction = async (a, b) => a + b;

wars.forEach(async (war) => {
  sum = await sumWarFunction(sum, war);
});

console.log(sum);

// Naively expected output: 18
// Actual output: 0
```

<aside>
💡 Here we see that rather than waiting to take returned from async operation `forEach()` callback function simply uses the initial value.

</aside>

# map method 😎

If `forEach()` was master of simplicity for looping over array. 

 `map` is the king of modifying the array. If you want to simply modify the content of the array in an easily debuggable and readable code `map` is the answer for this.

## Syntax 😋

### Using arrow functions map can be implemented in this way.

```jsx
map((element, index, array) => { /* ... */ })
```

### Let’s understand the parameters in the syntax

- `callbackFn`: Function which executes on each element and each time `callbackFn` is called returned value is added to the `newArray`
- `element`: Current element being worked on in array.
- `index` (optional): The index of element in array
- `array` (optional): Array upon which `map` was called.

**Return value :**

A new array is returned with each element being the result of a callback function.

### Example code using map method

```jsx
const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]

const map1 = arr.map(x => x.roll * 2);

console.log(map1)

// [
//   { name: 'Aashirwad', roll: 8 },
//   { name: 'Pankaj', roll: 146 },
//   { name: 'Ayush', roll: 140 },
//   { name: 'Nisha', roll: 66 }
// ]
```

Here we see that `map` is used not just to iterate over array but also the element of the array is modified in such a way that value is returned to a `newArray`.

## When to use  `map` 💪 (Pros over `forEach()`)

- Since they return values in `newArray` they are chainable.
- It is useful if the returned array is to be used.

## When to not use  `map` 🥲 (Cons)

- If a new array returned is of no use, then it is silly to use the map
- If the idea is to just iterate over values using `forEach()` is better.

## Gotchas! 😳

<aside>
💡 If the array that `map` was called upon is sparse, the resulting array will also be sparse keeping the same indices blank. Sparse means where some indexes have `undefined` values.

</aside>

<aside>
💡 It returns an entire so new array return statement is mandatory

</aside>

## Implementing Maps from scratch 😎

**It takes in a callback function with array element and returns a new array with operation defined in return statement used during the function call.**

```jsx

const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]
let mymap =(ar,callback)=>{
    const new_ar=[];
    ar.forEach((e) => {
        new_ar.push(callback(e))

        
    });
    return new_ar;

}

console.log(mymap(arr,(a)=>{
    return a.name
}))

// [ 'Aashirwad', 'Pankaj', 'Ayush', 'Nisha' ]
```

# `filter()` method 🥳

`filter()` is a kind of Mantri ( minister ) for kings, filtering out the `elements` before returning them in a `newArray` based on `callbackFn` returning only those values which satisfy a condition.

## Syntax 😇

### This is the syntax for using `filter()` using arrow function.

```jsx
filter((element, index, array) => { /* ... */ } )
```

### Let’s understand the parameters in the syntax

- `callbackFn`: Function is to test each `element` of the array and return a value that is either `true` to keep the element in `newArray` or `false` to not keep the element in the `newArray`.
- `element`: Current element being worked on in array.
- `index` (optional) : The index of element in array
- `array` (optional) : Array upon which `filter()` was called .

**Return value :**

A new array is returned elements that pass the test defined in `callbackFn`.

### Example Code using `filter()` method

```jsx
const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]

console.log(arr.filter(e => e.roll<20))

// [ { name: 'Aashirwad', roll: 4 } ]
```

Here we display only those `elements` on the console for which roll > 20. Thus `filtering` out other values.

## Pros of `filter()` 💫

- As we are operating with the element of the array, there is no need to define any index. Thus simplifying the code.
- No need of creating a new array to push elements.

## Cons of `filter()` 🥲

- If the new array returned is of no use, then it is silly to use filter better to just print the values using looping and if condition.

## Gotchas! 😳

<aside>
💡 It returns an entire so new array return statement is mandatory

</aside>

## Implementing `filter()` from scratch 😎

### Filter, as the name tells is used to filter out values from array-based on certain conditions i.e push only those values in a new array that satisfy the given condition in the return statement.

```jsx
const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]

const myfilter= function(arr,callback){
    const filter_arr=[];
    arr.forEach((e)=>{
        if(callback(e)){
            filter_arr.push(e);
        }

    })

    return filter_arr;
}

console.log(myfilter(arr,(e)=>{
    return e.roll>4
}))

// [
//   { name: 'Pankaj', roll: 78 },
//   { name: 'Ayush', roll: 70 },
//   { name: 'Nisha', roll: 33 }
// ]
```

# `reduce()` method 🥳

`reduce()` is like the ministry of a King. It executes a user-supplied “reducer” callback function on each element of the array, passing in return value after calculation and the final result is the single value after running the reducer across all elements of the array.

## Syntax 😇

### This is the syntax for using `reduce()` using arrow function.

```jsx
reduce((previousValue, currentValue, currentIndex, array) => { /* ... */ }, initialValue)
```

<aside>
💡 The reducer walks through the array element-by-element, at each step adding the current array value to the result from the previous step (this result is the running sum of all the previous steps) — until there are no more elements to add.

</aside>

### Let’s understand the parameters in the syntax

- `callbackFn` : Reducer Function which takes in four arguments
    - `previousValue`: initially this takes the `initialValue` or value of `array[0]`. Otherwise, it takes results from the value returned by the `callbackFn` in the previous call.
    - `currentValue`  : Value of the current element. On the first call, if `initialValue` is specified then `array[0]` or else it takes `array[1]`.
    - `currentIndex` : index position of the `currentValue.`
    - array: array to traverse
- `initialValue` (optional): Value which is to be given to previous on the first call.

**Return value :**

A new value is returned which results from applying `callbackFn` over the entire array.

### Example Code using `reduce()` method

```jsx
const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]

console.log(arr.reduce((previous,current)=>{
    return previous+current.roll

},0))

//185
```

Here we display only those `elements` on the console for which roll > 20. Thus `filtering` out other values.

## Pro Use Case of `reduce()` 🤑

- If an operation is to be applied on the entire array to return a particular value it is better to use it instead of defining a new function.

## Cons of `reduce()` 🥲

- The use case is very particular,i.e specific use case

## Gotchas ! 😳

<aside>
💡 It returns an error if an array with no elements is provided and no `initialValue` is given.

</aside>

<aside>
💡 If the array only has one element (regardless of position) and no `initialValue`is provided, or if `initialValue`is provided but the array is empty, the solo value will be returned without
 calling `callbackFn`.

</aside>

## Implementing `reduce()` from scratch 😎

### Reduce takes all the elements in an array and reduces them to a single value. We take in two values previous and current and return after performing an operation over them
So in the below example sum of all roll numbers we pass in a second value alongside callback function to use as the first value of previous.

```jsx
const arr=[
    {
        'name':'Aashirwad',
        'roll':4

    },
    {
        'name':'Pankaj',
        'roll':78

    },
    {
        'name':'Ayush',
        'roll':70

    },
    {
        'name':'Nisha',
        'roll':33

    },

]

let myreduce = function(arr,callback,initial){
    let acc =initial || 0;
    
    arr.forEach((e,i)=>{
        acc=callback(acc,arr[i])
    })
    return acc;
}

console.log(myreduce(arr,(previous,current)=>{
    return previous*current.roll

},1))

// 720720
```

## *These are some key points to keep my mind while using the four most important methods in JS arrays.*🤩

### Additional links

`forEach()` Method

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)

`map` method

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)

`filter()` method

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)

`reduce()` Method

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
