Array 'Superpowers' 🦸🏾
Tags: functional, beginners, react, javascript
Published: 2020-11-01 17:27:48

# Overview

Each of the methods covered in this post is incredibly powerful, in that they allow us to write less code that does more.

This is especially true as we start to work with 'realistic' sets of data - usually _arrays_ of _object literals._

# The 'Underling' Superpowers

These first 3 are somewhat useful for specific tasks. If we are going with this 🦸🏽‍♂️ analogy, these might be the 'apprentices,' - 'padawans,' if you will.

## `find`

Use `find` to..find and return the first _element_ in an _array_ that meets some true/false condition.

```javascript
const todos = [
  {
    "id": 1,
    "text": "Take out the trash",
    "completed": false
  },
  {
    "id": 2,
    "text": "Shop at Fresh Thyme",
    "completed": false
  },
  {
    "id": 3,
    "text": "Call Mom",
    "completed": true
  },
  {
    "id": 4,
    "text": "Mow lawn",
    "completed": true
  },
  {
    "id": 5,
    "text": "Litter Boxes Cleanup",
    "completed": false,
    "assignee": "Mary"
  }
]

// Find the first 'completed' task
todos.find(function(todo) {
  return todo.completed
})
```

We can rewrite using a 'one line' _fat arrow: `todos.find(todo => todo.completed)`_

The 🔑 to understanding this is the _**predicate** callback function: (todo => todo.completed)_.

A _**predicate** callback function_ is nothing but a _callback_ that `return`s based on upon _coercion_ to either `true` or `false`.

In other words:

1. _Iterate_ over `todos`, passing in each 'todo' one at a time. 
2. Have a look 👀 at `todo.completed`. If it's `true`, `return` this `todo`. If not, just move on.

**`find` will stop _iterating_ as soon as it finds the first 'match' It returns one single element from that _array (if there is one that meets the _predicate_ condition)._**

### Refactor ♻️ with Destructuring

`todos.find(({completed}) => completed)` 🤓

## `some`

Use this in a similar fashion to `find` 👆🏽, but here we just get back `true` or `false` as long as at least one _element_ in the _array_ meets the predicate condition.

So, given the same data set as above 👆🏽: `todos.some(({completed}` => completed)` will just give us back `true` because there at least **some** task has been completed ✅.

Like `find`, this one stops _iterating_ once it finds a 'truthy' _element._

## `every`

Same as `some` but makes sure that _all_ the _elements_ in the _array_ meet the _predicate._ This one continues to _iterate_ until it finds a 'fasle-y' element. 

Again, given, that data set 👆🏽, `todos.every(({completed}` => completed)` returns `false` b/c not **every** task has been completed ✅.

# The 'Main Roster' Superpowers

These next couple are used quite frequently - they are the 'workhorse' superpowers, getting a lot of things done.

**These _always_ return a new array.**

## `map`

We use this to perform some type of 'transform' on each and every element. 

Each _element_ is passed into a _callback function._ The _function_ does something to each _element,_ one at a time, creating a new _array_ along the way.

Let's start by 'mapping' over a simple _array_ of _numbers,_ 'transforming' each one by doubling it. This example is taken from [MDN](// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).

```javascript
const array1 = [1, 4, 9, 16];

// pass a function to map
const map1 = array1.map(x => x * 2);

console.log(map1);
// expected output: Array [2, 8, 18, 32]
```

`array1` and `map1` are totally separate _arrays._ `array1` has not been _mutated_ at all! 👏🏽

Now, let's do one with the `todos` data from above 👆🏽. This time we'll 'complete' all of the tasks: 

```javascript
todos.map(todo => {
  todo.completed = true;
  return todo;
})
```

This will create a new array with all of the _elements_ having: `completed: true`.

However, if we check the original `todos`, we will see that all of those 'todos' have been 'completed' also! 👎🏽

This is due to how JS treats _objects._ Essentially, the _references_ in memory 🧠 are shared.

Going into the particulars of 'copy/value vs reference' is a topic for another day, but since React relies heavily on 'no mutations,' let's at least see the code to fix this. We'll use the _object spread_ operator to create a 'fresh reference' to a totally new _object_ before updating `completed` to be `true`.

```javascript
todos.map(todo => {
  const currentTodo = {...todo}
  currentTodo.completed = true;
  return currentTodo;
})
```

In case you need more info on `...`:

{% link https://dev.to/codefinity/object-assign-and-spread-kcl %}

Now, the original _array_ and all of the objects therein are **not** _mutated,_ and we have a new _array_ with the 'completed' data. 🤓

⚠️ You may be tempted to try _object destructuring_ with `map`. This is usually not desirable as once you perform the _destructuring,_ you are limited to returning only those 🔑s that you _destructured._

For example 🙅🏽‍♂️:

```javascript
todos.map(({completed}) => {
  completed = true;
  return completed;
})
```
 would give us back: `[ true, true, true, true, true ]`. So, generally, stay away from _object destructuring_ when mapping.

Another common mistake is if you forget to explicitly return something from your 'map callback.' This will result in your 'mapped array' being full of `undefined`.

```javascript
todos.map(todo => {
  const currentTodo = {...todo}
  currentTodo.completed = true;
  // No return? Returning undefined!
})
```

## `filter`

This one works almost the same as `find` in that it uses a _predicate callback function._ However, rather than just returning a single element, `filter` will _traverse_ the entire _array,_ continuing to 'filter' 'truth-y' _elements_ into a 'fresh new array.'

Let's filter out all of the even numbers (numbers that are divisible by 2 with no remainder) from an _array_ of _numbers:_

```javascript
const nums = [1, 4, 9, 16]

const evens = nums.filter(num => !(num % 2))
```

Again, we rely on a _**predicate** callback function:_ `num => !(num % 2)`

1. We pass in each 'num'
2. Is `num % 2` 'false-y'? (i.e. Is the remainder 0?)
3. Add the _unary inverse operator: `!`_ to make it 'truthy' so that it `return`s to our 'filtered array.'

Again, `filter` `return`s the _element_ to a new _array_ **if** the _callback function_ `return`s `true`.

In this scenario, we ask, "Is it true that when we divide this number by 2 that the remainder is 'false-y'/0?"

Now, let's modify what we did for `find` earlier and `filter` our 'completed' tasks: `todos.filter(({completed} => completed)`.

Just with one line of code, we have completed our task. We have all of the original data in `todos`, and we have a separate 'filtered array' with just the 'completed' tasks. 👏🏽

## `map` - `filter` ⛓️

These 'superpowers' can join forces. This time: `//TODO: Filter out all 'incomplete' tasks and then assign those to 'Mary.'`

Once again, using: `todos` above 👆🏽:

```javascript
todos.filter(({completed}) => 

// Return if it's NOT completed
!completed).

// Continue the chain by mapping over the 'incomplete tasks'
map(todo => {
  const currentTodo = {...todo};
  currentTodo.assignee = "Mary";
  return currentTodo;
})
```

The results: 

```javascript
[
  {
    id: 1,
    text: 'Take out the trash',
    completed: false,
    assignee: 'Mary'
  },
  {
    id: 2,
    text: 'Shop at Fresh Thyme',
    completed: false,
    assignee: 'Mary'
  },
  {
    id: 5,
    text: 'Litter Boxes Cleanup',
    completed: false,
    assignee: 'Mary'
  }
]
```

# The 'Leader' 👑 of the Array Superpowers 🦸🏽‍♂️

One reason why `reduce` is the most powerful of all of these is b/c, _technically_ it can do the job of any of the 👆🏽. That being said, use the right tool for the right job - just b/c you _can (and it's quite challenging, actually),_ doesn't mean that you should.

Use `reduce` to...reduce your _array_ into one single 'accumulated thing.'

One of the differences is that the `reduce` _callback function_ **requires** two _parameters:_

1. An 'accumulator' to keep track of the '🏃🏽‍♂️ total.'
2. A 'current element' to keep track of...the current element in the _array_ as we _traverse._

For simplicity, we start with the most basic example, summing up numbers in an _array:_

```javascript
const nums = [1, 2, 3, 4];

const total = nums.reduce((
  // 'total' is initialized with the value of the first element -'1'
  total, 

// 'num' initializes as the 2nd element's value - '2'
num) => {
  // Add 'total' to 
  total += num;
  return total;
})
```

There is a lot more to `reduce` that we can do. This example just scratches the surface. In the next post, we'll do some more 'practical'/intermediate things with `map`, `filter` and `reduce`.