Array.prototype.map()
Builds a new array by running a function over every element of the original.
map(callbackFn)
map(callbackFn, thisArg)- Added in JavaScript ES5 (2009)
Parameters
| Parameter | Type | Description |
|---|---|---|
$callbackFn | Function | Function run for each element. Called with (element, index, array); its return value becomes the element at that index in the new array. |
$thisArgoptional | any= undefined | Value to use as this when executing callbackFn. Ignored by arrow functions, which take this from the enclosing scope. |
Return value
ArrayA new array where each element is the value returned by callbackFn for the element at the same index.
Errors
Nothing of its own — any error thrown by callbackFn propagates and aborts the iteration.
map() is the workhorse for turning one array into another of the same length. It never mutates the receiver: it allocates a fresh array and fills index i with whatever your callback returned for index i. Because the length is fixed by the input, map() can never drop or add items — reach for filter() when you need fewer, and reduce() when you need a single value.
When to reach for it
- Reshaping API records into the shape your UI expects.
- Pulling one field out of every object.
- Formatting numbers or dates for display.
What trips people up
The callback receives three arguments, not one, so passing a built-in that takes a second parameter misfires: ["10","10","10"].map(parseInt) gives [10, NaN, 2] because the index is handed to parseInt as the radix. Use map(Number) or an explicit arrow.
An arrow with a braced body returns undefined unless you write return, so map(x => { x.done = true }) yields an array of undefined. To return an object literal concisely, wrap it in parentheses: map(x => ({ ...x })).
Finally, ignoring the returned array is a smell — if you only want side effects, forEach() says so more clearly.
Example
When to use it
- Turn an array of user records into an array of display names
- Apply tax or currency formatting to every price in a cart
- Convert raw API rows into the shape a chart component expects
- Wrap each value in an object with an added computed field
Frequently asked questions
Does map() change the original array?
No — map() returns a new array and leaves the receiver alone. The catch is that it is a shallow copy: if the callback returns the same object references, mutating one of those objects still affects the original array's elements.
How do I skip elements inside map()?
You can't — map() always produces an array of the same length. Filter first (arr.filter(cond).map(fn)), or use flatMap() and return [] for the items you want dropped.
Why does my map() with async return an array of Promises?
Because an async callback returns a Promise, and map() stores whatever the callback returned. Wrap the result: const values = await Promise.all(arr.map(async (x) => …)).
More examples
The parseInt trap
The first line prints [10, NaN, 2]: map() passes the index as parseInt's second argument, so it parses in base 0, base 1 and base 2. Number takes only one argument, so it prints [10, 10, 10], as does the explicit arrow that pins the radix to 10.
console.log(["10", "10", "10"].map(parseInt));
console.log(["10", "10", "10"].map(Number));
console.log(["10", "10", "10"].map((s) => parseInt(s, 10)));Using the index, and how sparse slots survive
The first log prints ['0:a', '1:b', '2:c'], showing the second callback argument. The sparse array prints [2, <1 empty item>, 6] — the callback is never invoked for the hole, so the hole is copied through untouched, and the length stays 3.
const letters = ["a", "b", "c"];
console.log(letters.map((ch, i) => `${i}:${ch}`));
const sparse = [1, , 3];
console.log(sparse.map((x) => x * 2));
console.log(sparse.map((x) => x * 2).length);
Discussion