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.
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
| Parameter | Required | Description |
|---|---|---|
callbackFn | Yes | Function executed for each element. Its return value becomes the matching element of the new array. |
→ element | — | The current element being processed. |
→ index | — | The index of the current element (0-based). |
→ array | — | The array map() was called on. Rarely needed; handy for looking at neighbours. |
thisArg | No | Value 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() | |
|---|---|---|
| Returns | a new array | undefined |
| Purpose | transform into a new array | side effects (log, save, mutate) |
| Chainable | yes (returns an array) | no |
| Use when | you need the results | you 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
forloop can be marginally faster, butmap()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, useforEach()orfor...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?
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?
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?
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.