JAVASCRIPT IRL: Examples of JavaScript's map function in real life
Tags: javascript, array, map, tips
Published: 2021-01-06 17:08:14

JavaScript array methods are super useful, and learning how to use them can really help improve the readability of your code. However, since most developers start off with basic `for` loops and `while` loops, making the switch to more abstract constructions like `map`, `reduce`, and `filter` can be quite difficult. There are lots of posts describing these functions and giving examples, but very few actually compile a list of these being used in a real codebase. It's all well and good to see how you can increment every element of an array using `map`, but it's not so often that you'll actually be using that in a codebase.

This is going to be a small three-part series where I go over real-life examples of `map`, `reduce`, and `filter`. Let me know in the comments what you thought of this post and if you'd like me to change anything for the next two posts! Without further ado, here are some examples of `map` in a real production environment.

The `map` function is called on an array, and takes in one parameter: a callback. It performs this callback function on every element in the array, and returns a new array of the same length as the original. The value at each index in the new array is the result of the callback on the element at that index in the original array. Let's take a look at a trivial example before we dive in:

#### A trivial example

Okay, so I know I said you wouldn't be incrementing an array by 2 in a codebase, **but**(!) for the sake of posterity, I thought I might add it anyway:

Hey, it looks like you're on a slightly narrower screen. The code blocks below might not look too good, but the rest of the article should be fine. You can hop on a wider screen if you want to follow along. I'm not going anywhere (promise).
```javascript
      const arr = [1,2,3];
      const newarr = arr.map(el => el + 2);

      console.log(newarr); // => [3,4,5]
```
In this case, the callback returns the value of `el + 2`; the new array thus contains the elements of the old array but with 2 added to them.

Now let's look at some real-life examples:

#### Deleting caches with a service worker

In this example, the service worker for a webpage needs to delete any outdated caches. Because it uses `Promises` and asynchronous programming, the return value looks a little different. However, the concept of the `map` function remains the same:
```javascript
      self.addEventListener('activate', function(event) {
        // Delete all caches that aren't named currentCache.
        event.waitUntil(
          caches.keys().then(cacheNames => {
            return Promise.all(
              cacheNames.map(cacheName => { // map function
                if (cacheName != currentCache) {
                  console.log('Deleting out of date cache:', cacheName);
                  return caches.delete(cacheName); // returns a callback to delete this cache
                }
              })
            );
          })
        );
      });
```
While the nested callbacks can make this look intimidating, we can see that the `map` function is actually super simple: if the `cacheName` is not equal to the `currentCache`, we return a callback that deletes the cache. Otherwise, we return `null`. Without the `map` function, we'd have to use a for loop and a temporary array, and push every element to the temporary array if it satisfied the condition.

Let's look another example:

#### Saving nested objects to local storage

As part of a What-You-See-Is-What-You-Get (WYSIWYG) editor that I've been making, I decided to store the actual data in local storage. If you're not sure what local storage is, it's a super useful storage API exposed at `window.localStorage` where you can set key-value pairs for retrieval at a later date. The only issue with this is that my content was wrapped in a data binding — a complicated structure, but suffice it to say that I had an array of `Binding` objects, and the content that I _actually_ wanted to store was in the nested property `Binding.boundobj.obj`. This is the perfect use case for `map`:
```javascript
      const saveToStorage = () => {
        localStorage.setItem(contentName, JSON.stringify(contentobj.map(binding => binding.boundobj.obj)));
      }
```
This is a super simple fix: instead of creating a complicated `for` loop where I push the nested property into a new array, I can create a one-liner just by using the `map` function to return the nested property for each element.

Let's take a look at one final example:

#### To create a table in React

This code snippet is taken from a React component designed to create a custom table with a heading row. You can see it in action at [Terraling](https://ui.terraling.com/groups/7/lings/816); scroll down to any of the Property tables to see how the headers are visually distinct from the table data. This is what some of the code to generate those tables looks like:
```javascript
      <div className={`headers row row-${keys.length}`}>
        {
          headers.map((header, i) => {
            return (
              <span key={i} className="header name">{header}</span>
            )
          })
        }
      </div>
```
Since the header data is passed into the component via the array `headers`, I needed to transform each element from a string into an entire `span` element. While this can be done with a `for` loop, using the `map` construction allows for more readable and concise code. Anyone who reads the code is better able to understand what happens to each element in the `headers` array.

#### Wrapping it up

I hope these examples gave you an idea of how the `map` function is really used in a codebase, and how it can help make code more readable and concise. It truly is a versatile construction, and I highly recommend getting familiar with it by using it in your own code. Let me know down in the comments if you have any interesting uses for the `map` function, and keep an eye out for the next two posts in the series!

As always, don't forget to follow me for more content like this. I'm currently writing on [dev.to](https://shaile.sh/devto) and [Medium](https://shaile.sh/medium), and your support on either platform would be very much appreciated. I also have a [membership](https://www.buymeacoffee.com/shailesh/posts) set up, where you can get early previews of articles and exclusive access to a whole bunch of resources. Also, if you've particularly enjoyed this post, consider supporting me by [buying me a coffee](https://shaile.sh/coffee). Until next time!