Write more readable code in JavaScript using map array method
Tags: javascript, map, array, webdev
Published: 2020-05-09 09:35:39


The array is one of the most common data types in JavaScript. There are many useful methods associated with arrays like `map`, `filter`, `reduce`, `find`, `some`, `forEach`, `push`, `pop`, etc. In this article, I am gonna talk about `map` method.

`map` is a non-mutating method. So, if you do things right, the main array elements will not be affected (modified).

## Map

`map` method creates a new array with the same length from the original array. It is very helpful when you need to create a new array from the original array and you also want to do some operations on each item in the array.

`map` structure:
```jsx
const resultingArray = oldArray.map((currentValue, index, oldArr) => {
  // return an element
}, this);
```

`map` expects two arguments. 
1. `callback` function. This does the main job. We can use traditional function. Or `ES6` `arrow` function. In our case, `(currentValue, index, oldArr) => { // return an element }` this is the `callback` function.
2. `this` argument. You can use it as `this` value in the `callback` function. It is optional and rarely used.

Now, `callback` function has 3 arguments. 
- `currentValue`. This is the element or value being processed in every loop iteration.
- `index`. This is optional. This represents the index of `currentValue`.
- `array`. This is also an optional and rarely used argument. This represents the original array on which `map` method was applied.

After processing, `map` returns the `resultingArray` without modifying `oldArray`.



Example:
```jsx
const persons = [
  { name: "Jane", age: 19 },
  { name: "John", age: 21 },
  { name: "Rick", age: 17 },
  { name: "David", age: 22 },
];

const names = persons.map(person => person.name);
/*
* ES5 function syntax:
* const names = persons.map(function (person) {
*   return person.name;
* });
*/

console.log(names);
// output: ['Jane', 'John', 'Rick', 'David']
```

In this example, we have created a new array containing only names. In the `map` function, I am passing a function which takes a person and returns that person's name. So, it loops through the array, for every element in that array, it returns only the `name` property hence creates a new array with only names.


If we wanted an array containing name and a flag to determine if the person is 20 plus aged, then we could do the following:

```jsx
const persons = [
  { name: "Jane", age: 19 },
  { name: "John", age: 21 },
  { name: "Rick", age: 17 },
  { name: "David", age: 22 },
];

const newPersons = persons.map(person => {
  return { name: person.name, twentyPlus: person.age > 20 };
});

/*
* ES5 function syntax: 
* const newPersons = persons.map(function (person) {
*   return { name: person.name, twentyPlus: person.age > 20 };
* });
*/

console.log(newPersons);
/* output:
* [
*   { name: 'Jane', twentyPlus: false },
*   { name: 'John', twentyPlus: true },
*   { name: 'Rick', twentyPlus: false },
*   { name: 'David', twentyPlus: true }
* ]
*/
```


In this example, we have created a new array containing names and a flag to determine if the person's age is more than twenty or not. In the `map` function, I am passing a function which takes a person and returns a new object. That object contains the person's name and a flag to determine if the person's age is more than twenty or not. So, it loops through the array, for every element in that array, it returns the `name` property and that boolean value wrapped in an object hence creates a new array with names and `twentyPlus` flag.

Now in the first example, I used shorthand syntax to return name and in the second example, I returned the new object explicitly. 

We can use normal `callback` function instead of `ES6` `arrow` function. But, arrow functions are more readable.

I will now share another example with `index` and `array` in `callback` function:

```jsx
const persons = [
  { name: "Jane", age: 19 },
  { name: "John", age: 21 },
  { name: "Rick", age: 17 },
  { name: "David", age: 22 },
];

// index will add 0, 1, 2, 3 respectively and array.length will
// add 4 for every new item's modifiedAge property
const newPersons = persons.map((person, index, array) => {
  return { name: person.name, modifiedAge: person.age + index + array.length };
});

// ES5 function syntax:
// const newPersons = persons.map(function (person, index, array) {
//   return { name: person.name, modifiedAge: person.age + index + array.length };
// });

console.log(newPersons);
// Output:
// [
//   { name: 'Jane', modifiedAge: 23 },
//   { name: 'John', modifiedAge: 26 },
//   { name: 'Rick', modifiedAge: 23 },
//   { name: 'David', modifiedAge: 29 }
// ]

```


All modern browsers support `map`. You can find complere reference <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Browser_compatibility" title="map browser compatibility" target="_blank" rel="noopener noreferrer">here</a>

## When not to use map

`map` is not for every situations. When you do not want or need to return value or create new array with the same length, map should not be used. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach" title="forEach" target="_blank" rel="noopener noreferrer">forEach</a> or other array methods should be more suitable on those situations.

## Why map is more readable

Suppose, you are creating a new array of persons with name and twentyPlus boolean flag like our second example with traditional `for` loop. Then, the code should be like this:

```jsx
let newPersons = [];
for (let i = 0; i < persons.length; i++) {
  let person = {
    name: persons[i].name,
    twentyPlus: persons[i].age > 20,
  };
  newPersons.push(person);
}
```

You have to go through the whole code to understand that I am creating a new array. And the main logic of creating that array resides inside `person` object creation part inside the `for` loop. You will also have to check if I have written a `break` or `continue` statement to skip any particular value or not. 

On the other hand, as soon as you see a `map` method, you know that I am creating a new array of the same length. As new array must be of the same length, I cannot use `break` or `continue` to skip values.

```jsx
const newPersons = persons.map(person => {
  return { name: person.name, twentyPlus: person.age > 20 };
});
```

When we use `map`, we can focus more on logic cause it's purpose is defined. 

## Conclusion

`map` is a very handy array method. It has a specific purpose. That purpose is: creating a new (modified) array with the same length. Whenever we need this functionality in our code, we should be using `map` for better readability and maintainability.