Episode 1 — Fundamentals / 1.22 — Array Methods
1.22.a — map()
In one sentence:
map()calls a function on every element and returns a brand-new array of the same length containing each transformed value.
Navigation: ← 1.22 Overview · 1.22.b — filter() →
1. What map() does
map() iterates through every element, passes it to your callback, and collects the return values into a fresh array. The original array is never touched.
const nums = [1, 2, 3, 4];
const doubled = nums.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8]
console.log(nums); // [1, 2, 3, 4] ← unchanged
Think of it as a conveyor belt: each item goes in, gets transformed, and comes out the other end.
2. Syntax
const newArray = arr.map(callback(element, index, array));
| Parameter | Description |
|---|---|
element | The current element being processed |
index | (optional) The index of the current element |
array | (optional) The original array map was called on |
| Return | A new array with each element being the result of the callback |
The callback must return a value. Whatever you return becomes the element at that position in the new array.
const words = ["hello", "world"];
// Using all three parameters
const tagged = words.map((word, index, arr) => {
return `${index + 1}/${arr.length}: ${word}`;
});
console.log(tagged);
// ["1/2: hello", "2/2: world"]
3. Does NOT mutate the original
This is a core guarantee:
const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.18);
console.log(prices); // [10, 20, 30] ← same
console.log(withTax); // [11.8, 23.6, 35.4] ← new array
This makes map safe for functional programming and React state updates where immutability matters.
4. Return value is always a new array of the same length
No matter what your callback does, map always returns an array with exactly as many elements as the original.
const nums = [1, 2, 3];
const result = nums.map(n => {
if (n > 2) return n * 10;
// oops, no explicit return for n <= 2
});
console.log(result); // [undefined, undefined, 30]
// ^^^^^^^^^ still 3 elements!
If you want fewer elements, use filter. If you want a single value, use reduce.
5. Common use: transforming data shapes
One of the most frequent real-world uses is reshaping objects from one form to another.
// API response
const users = [
{ id: 1, first_name: "Alice", last_name: "Smith", email: "alice@example.com" },
{ id: 2, first_name: "Bob", last_name: "Jones", email: "bob@example.com" },
{ id: 3, first_name: "Carol", last_name: "White", email: "carol@example.com" },
];
// Transform to UI-friendly shape
const displayUsers = users.map(user => ({
id: user.id,
fullName: `${user.first_name} ${user.last_name}`,
avatar: user.first_name[0] + user.last_name[0],
}));
console.log(displayUsers);
// [
// { id: 1, fullName: "Alice Smith", avatar: "AS" },
// { id: 2, fullName: "Bob Jones", avatar: "BJ" },
// { id: 3, fullName: "Carol White", avatar: "CW" },
// ]
6. Mapping to JSX in React (preview)
If you continue to React, map becomes your primary tool for rendering lists:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.fullName}</li>
))}
</ul>
);
}
Every React list render is basically a map call. The key prop tells React which element changed.
7. map vs forEach — key difference
| Feature | map() | forEach() |
|---|---|---|
| Returns | New array of transformed values | undefined |
| Use for | Transforming data | Side effects (logging, DOM updates) |
| Chainable | Yes (arr.map(...).filter(...)) | No (returns undefined) |
| Original mutated | No | No |
Rule of thumb: If you need the result, use map. If you just need to do something for each element, use forEach.
// WRONG: using forEach when you need the result
const result = [];
[1, 2, 3].forEach(n => result.push(n * 2)); // works but messy
// RIGHT: use map
const result2 = [1, 2, 3].map(n => n * 2); // clean and declarative
8. Chaining with other methods
Because map returns an array, you can chain more array methods:
const products = [
{ name: "Laptop", price: 999, inStock: true },
{ name: "Phone", price: 699, inStock: false },
{ name: "Tablet", price: 499, inStock: true },
{ name: "Watch", price: 299, inStock: true },
];
// Chain: filter in-stock → map to formatted strings → sort alphabetically
const available = products
.filter(p => p.inStock)
.map(p => `${p.name}: $${p.price}`)
.sort();
console.log(available);
// ["Laptop: $999", "Tablet: $499", "Watch: $299"]
Read the chain top-to-bottom: filter first (reduces the set), then map (transforms), then sort.
9. Common mistake: forgetting to return
With arrow functions using curly braces {}, you need an explicit return:
// BUG: no return statement
const names = ["alice", "bob"].map(name => {
name.toUpperCase(); // computed but not returned!
});
console.log(names); // [undefined, undefined]
// FIX 1: add return
const names2 = ["alice", "bob"].map(name => {
return name.toUpperCase();
});
// FIX 2: use implicit return (no braces)
const names3 = ["alice", "bob"].map(name => name.toUpperCase());
Another common mistake with objects — you need parentheses for implicit return:
// BUG: braces are interpreted as function body, not object literal
const pairs = [1, 2, 3].map(n => { value: n });
console.log(pairs); // [undefined, undefined, undefined]
// FIX: wrap object literal in parentheses
const pairs2 = [1, 2, 3].map(n => ({ value: n }));
console.log(pairs2); // [{ value: 1 }, { value: 2 }, { value: 3 }]
10. Real-world examples
Double all numbers
const nums = [4, 9, 16, 25];
const doubled = nums.map(n => n * 2);
// [8, 18, 32, 50]
Extract names from objects
const students = [
{ name: "Alice", grade: "A" },
{ name: "Bob", grade: "B" },
{ name: "Carol", grade: "A" },
];
const names = students.map(s => s.name);
// ["Alice", "Bob", "Carol"]
Format prices
const rawPrices = [19.99, 5.5, 100, 0.99];
const formatted = rawPrices.map(price =>
`$${price.toFixed(2)}`
);
// ["$19.99", "$5.50", "$100.00", "$0.99"]
Convert Celsius to Fahrenheit
const celsius = [0, 20, 37, 100];
const fahrenheit = celsius.map(c => (c * 9/5) + 32);
// [32, 68, 98.6, 212]
Add computed property to objects
const orders = [
{ item: "Shirt", qty: 2, unitPrice: 25 },
{ item: "Pants", qty: 1, unitPrice: 50 },
{ item: "Socks", qty: 5, unitPrice: 5 },
];
const withTotals = orders.map(order => ({
...order,
total: order.qty * order.unitPrice,
}));
// [
// { item: "Shirt", qty: 2, unitPrice: 25, total: 50 },
// { item: "Pants", qty: 1, unitPrice: 50, total: 50 },
// { item: "Socks", qty: 5, unitPrice: 5, total: 25 },
// ]
11. Using the index parameter
const letters = ["a", "b", "c"];
const numbered = letters.map((letter, index) => `${index + 1}. ${letter}`);
// ["1. a", "2. b", "3. c"]
Be careful: do not accidentally use the index as a key for non-stable lists in React (covered in React modules).
12. map with existing functions
You can pass a named function directly:
function square(n) {
return n * n;
}
const nums = [1, 2, 3, 4, 5];
const squares = nums.map(square);
// [1, 4, 9, 16, 25]
Gotcha with parseInt:
// Surprising behavior!
["1", "2", "3"].map(parseInt);
// [1, NaN, NaN] ← because parseInt receives (element, index) as (string, radix)
// Fix: wrap in arrow function
["1", "2", "3"].map(s => parseInt(s, 10));
// [1, 2, 3]
Key takeaways
map()transforms every element and returns a new array of the same length.- It never mutates the original array.
- Always return a value from the callback — otherwise you get
undefinedin the new array. - Use
mapwhen you need the result; useforEachwhen you only need side effects. - Wrap object literals in parentheses for implicit arrow-function returns:
n => ({ key: n }). mapis the workhorse of React list rendering and data transformation pipelines.
Explain-It Challenge
Explain without notes:
- What does
map()return if the callback never has areturnstatement? - Why is
[10, 20, 30].map(n => { doubled: n * 2 })broken, and how do you fix it? - When would you pick
forEachovermap?
Navigation: ← 1.22 Overview · 1.22.b — filter() →