Reference

Reference · JavaScript · Arrays

Array.prototype.map()

map() builds a new array by running a function on every element of an existing one. It never changes the original — it returns a transformed copy of exactly the same length. This is the standard way to turn one array into another in JavaScript.

XCODXReference · Updated

Definition

Array.prototype.map() is the workhorse of array transformation in JavaScript. You give it a function; it calls that function once for every element of the array, collects the return values, and hands you back a brand-new array of those results. If the input has five elements, the output has five elements — element *i* of the output is whatever your function returned for element *i* of the input.

Two guarantees make map() easy to reason about. First, it is non-mutating: the array you call it on is never changed — you always get a new array. Second, the result is always the same length as the input. That predictability is why map() is the backbone of data pipelines: an array of API records becomes an array of view models, an array of prices becomes an array of formatted strings, an array of numbers becomes an array of DOM nodes.

Syntax

// The callback runs once per element; its return value
// becomes the matching element of the new array.
array.map(callbackFn)
array.map(callbackFn, thisArg)

// callbackFn is called with three arguments:
array.map((element, index, array) => {
  return /* the transformed value for this element */;
})

The value your callback returns becomes the corresponding element of the new array. If a code path in your callback doesn't return anything, that position becomes undefined — a common source of "why is my array full of undefined?" bugs (see below).

Parameters

ParameterRequiredDescription
callbackFnYesFunction executed for each element. Its return value becomes the matching element of the new array.
elementThe current element being processed.
indexThe index of the current element (0-based).
arrayThe array map() was called on. Rarely needed; handy for looking at neighbours.
thisArgNoValue to use as this inside callbackFn. Irrelevant for arrow functions, which don't have their own this — so you almost never need it.

You don't have to use all three callback arguments — most callbacks use only element. But because map() *passes* all three, be careful when handing it an existing function that accepts more than one argument (the classic parseInt trap, below).

Return value

A new array where each element is the value your callback returned for the element at that index.

  • Same length as the input — one output element per input element, always.
  • The original array is never modified.
  • It's a shallow transformation: if your callback returns the same object references (or you don't clone them), the new array holds the same objects — mutating one still affects both arrays.
  • In a sparse array (one with holes), map() skips the holes: your callback is not called for an empty slot, and the slot stays empty in the result.

Examples

Every example below runs live — edit the code and press Run to see the output update.

Transform each element

The canonical use: turn every value into a new one. Here we apply tax to each price and round to two decimals.

Pull one field out of a list of objects

Extracting a single property from an array of objects ("plucking") is one of the most common map() jobs in real code — turning API records into just the ids, names, or emails you need.

Use the index

The second argument is the index, which is handy for numbering, alternating styles, or pairing an element with its position.

Update objects immutably

map() is the standard tool for immutable updates in React and other state libraries: produce a new array of new objects instead of mutating in place. Note the parentheses around the object literal — without them the arrow's { } is read as a function body, not an object.

Chain with filter()

Because map() returns an array, it composes naturally with other array methods. A filter() then map() (or the reverse) expresses a whole pipeline in one readable expression.

Browser & runtime support

map() vs forEach()

They look similar but express different intent. map() returns a new array of your callback's return values. forEach() returns undefined and exists purely for side effects. Use map() to build a value; use forEach() (or for...of) to just run code.

map()forEach()
Returnsa new arrayundefined
Purposetransform into a new arrayside effects (log, save, mutate)
Chainableyes (returns an array)no
Use whenyou need the resultsyou don't need a result

Gotcha: the parseInt trap

A famous bug. Because map() calls your function with three arguments (element, index, array) and parseInt takes a second argument (the radix), the index gets used as the radix — producing nonsense.

Gotcha: an array full of undefined

If your callback doesn't return a value on some path, that element becomes undefined. The usual causes are a block body without return, or writing item => { ...item } (a block containing a stray spread) when you meant item => ({ ...item }).

// ❌ block body, no return -> [undefined, undefined, ...]
users.map(u => { u.name });

// ✅ either return explicitly...
users.map(u => { return u.name; });
// ✅ ...or use an expression body
users.map(u => u.name);

Sparse arrays

map() does not call your callback for holes in a sparse array, and it preserves those holes in the result — so the callback runs fewer times than length suggests.

Performance & tips

  • Keep the callback pure — return a value, avoid side effects. Side-effectful map() is hard to read and easy to get wrong.
  • For very hot paths over huge arrays, a plain for loop can be marginally faster, but map() is plenty fast for virtually all UI and data work — reach for the loop only if profiling tells you to.
  • Don't call map() just to iterate — if you're ignoring the returned array, use forEach() or for...of.

Browser & runtime support

map() has been part of the language since ECMAScript 5 (2009). It works in every modern browser and every maintained version of Node.js, with no polyfill required.

Frequently asked questions

Does map() change the original array?
No. map() always returns a new array and leaves the original untouched. But it's a shallow copy: if the array holds objects and your callback returns those same objects, mutating one still affects both arrays. Return new objects (e.g. with spread) for a fully independent result.
What's the difference between map() and forEach()?
map() returns a new array built from your callback's return values and is chainable; forEach() returns undefined and is only for side effects. Use map() when you want the transformed array, forEach() or for...of when you just want to run code for each element.
Why did map() return an array of undefined?
Your callback isn't returning a value on every path. The usual culprits are a block body without a return, or writing x => { ...x } when you meant x => ({ ...x }). Use an expression body or add an explicit return.
Why does ['1','2','3'].map(parseInt) give [1, NaN, NaN]?
map() passes three arguments (element, index, array), and parseInt's second argument is the radix — so the index becomes the radix. Use .map(Number) or .map(s => parseInt(s, 10)) instead.
How do I get both the item and its index?
The second callback argument is the index: array.map((item, index) => ...). The third is the whole array if you need to peek at neighbours.
Can I use async/await inside map()?
map() itself is synchronous. Passing an async callback gives you an array of Promises — combine it with Promise.all: await Promise.all(items.map(async x => await work(x))).
How do I transform only some elements?
map() always returns the same number of elements. To drop some, filter() first (or after), or use flatMap() and return an empty array for elements you want to remove.