The JavaScript map() Method

Abstract image used to represent The JavaScript map() Method
Image by Annie Spratt.

It feels like a very long time since I wrote about JavaScript's filter() method, so in the interest of completeness, I'm looping back to cover two other array manipulation methods: reduce(), and map(). Today, it's the turn of map() which although simple at its core is an extremely powerful thing to have in your toolbox.


Understanding map()

At its heart, JavaScript's map() method transforms an array. It takes each element, applies the callback function you've provided to the element, and then assembles that output into a new array.

Fundamentals

Array.prototype.map() calls the supplied callback for each present index in the array's initial length, then puts the return values into a new array. It skips empty slots in a sparse array, leaving corresponding slots empty in the result. A present value of undefined is still visited.

Syntax

Here's what the syntax looks like:

const newArray = array.map((currentValue, index, arr) => currentValue, thisValue);

This breaks down as follows:

  • currentValue: The current element being processed in the array;
  • index (optional): The index of the current element being processed;
  • arr (optional callback parameter): The array on which map() was called.
  • thisValue (optional second argument to map()): The this value used for a normal function callback. Arrow functions, including the one shown above, inherit this from their surrounding scope and ignore this argument.

A Simple Example

As a very basic example, imagine that you have an array of numbers, and that you need to find the square of each. Here's how map() could be used:

const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map((number) => number * number);

console.log(squaredNumbers);
//=> [1, 4, 9, 16, 25]

Essentially, map() loops over each item within the numbers array, multiplies it by itself, and then includes that result in squaredNumbers.


A More Complex Example

For a slightly more complicated example, imagine that you're dealing with a set of products where you need to apply a 10% discount to the price of each. We can use map() to loop over each product within an array, retain all the other fields (using the ... spread syntax), and multiply the price field by 0.9:

const products = [
  { name: 'MacBook', price: 2000 },
  { name: 'iPhone', price: 750 },
  { name: 'iPad', price: 1200 },
];

const discountedProducts = products.map((product) => ({
  ...product,
  price: product.price * 0.9,
}));

console.log(discountedProducts);
/*
  Output:
  [
    {
      name: 'MacBook',
      price: 1800,
    },
    {
      name: 'iPhone',
      price: 675,
    },
    {
      name: 'iPad',
      price: 1080,
    },
  ];
*/

Looping over data in JSX with map()

If you've spent any time developing in React, you will no doubt already be familiar with (or at least have come across) the practice of using map() within JSX to render out lists of elements. It's an elegant application of map() which perhaps falls outside of the more conventional uses I've discussed until now, so it deserves a discussion here...

Why Use map() in JSX?

React is declarative and encourages declarative programming where you describe what the UI should look like for given states rather than detailing the steps to achieve it (which would be 'imperative programming'). Using map() to loop over a dataset and define the output for each aligns very neatly with this declarative philosophy, allowing us as developers to transform arrays of data into arrays of components.

How It Works

In JSX, we can use map() to iterate over an array of data, and return a new array of React elements or components. Each is then rendered into the UI. It's a pattern that is particularly useful for lists, tables, or any collection of similar elements derived from an array. It's how I populate a lot of the different aspects of my own personal website here. For example, the Article Listing pages, the Project Listing page, and even the categories and related articles that are listed at the bottom of this page.

An Example

Imagine you have a list of clients in an array that you want to display in a simple unordered list:

const clients = ['IMG Licensing', 'Apple', 'Virgin Atlantic', 'BBC', 'Cisco'];

The React component below is written in TypeScript with JSX:

const ClientsList = ({ clients }: { clients: string[] }) => (
  <ul>
    {clients.map((client, i) => (
      <li key={i}>{client}</li>
    ))}
  </ul>
);

When rendering a list, give each sibling a stable, unique key. React uses it to match that item between renders, including when items are inserted, removed or reordered. This concerns component identity and reconciliation; it does not promise that the browser will avoid a repaint.

For the sake of this fixed example, I'm using the index (i). If the list can be reordered or have items inserted or removed, use an identifier that belongs to the item itself. Otherwise the same index can come to represent a different client.


Tips for using map()

Transformation Power

map() is all about the transformation of data. This is likely the method you need when you need to convert data from one form to another.

Chainability

Much like filter(), map() can be chained with other array methods, such as filter(), or reduce(), to perform more complex data transformations.

Performance Considerations

The callback runs for each present index, so its work matters when mapping a large array. Filtering first can reduce that work when excluded items genuinely do not need the transformation, but it also adds its own pass. Choose the sequence that matches the data operation, and measure if performance matters.


The Wrap‑up

When it comes to transforming data from one structure to another, map() is very likely to be the tool you're after.


Have a complex web platform issue?

Tell me what is blocked, what has changed, and what needs to be true after the fix. I'll come back with a practical next step.