map
In the previous lesson, you learned that .forEach() is useful when you want to do something with every item in an array.
For example:
const numbers = [1, 2, 3];
numbers.forEach((number) => {
console.log(number * 2);
});This logs doubled values, but it does not create a new array.
When you want to transform every item and get a new array back, use .map().
What Is map?
map is an array method that creates a new array by transforming each element in the original array.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((number) => {
return number * 2;
});
console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4]The original array is unchanged.
The new array contains the values returned by the callback.
You can read .map() like this:
Take each item.
Transform it.
Put the transformed value into a new array.Basic Syntax
The syntax looks like this:
const newArray = originalArray.map(function (currentValue, index, array) {
return transformedValue;
});The callback can receive three arguments:
| Argument | Meaning | Common? |
|---|---|---|
currentValue |
The current element being processed | Yes |
index |
The index of the current element | Sometimes |
array |
The original array map was called on |
Rarely |
The most important rule is:
The callback must return the value you want in the new array.Basic Example: Doubling Numbers
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((number) => {
return number * 2;
});
console.log(doubled); // [2, 4, 6, 8]Each callback return value becomes one element in the new array.
| Original value | Callback returns | New array value |
|---|---|---|
1 |
2 |
2 |
2 |
4 |
4 |
3 |
6 |
6 |
4 |
8 |
8 |
The new array has the same length as the original array.
console.log(numbers.length); // 4
console.log(doubled.length); // 4Concise Arrow Function Syntax
When the callback only returns one expression, you can use a concise arrow function.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((number) => number * 2);
console.log(doubled); // [2, 4, 6, 8]This:
(number) => number * 2is the short version of:
(number) => {
return number * 2;
}Both are correct.
Use the longer version when the transformation needs multiple lines.
Use the concise version when the transformation is simple.
map Does Not Mutate the Original Array
map returns a new array.
It does not change the original array by itself.
const prices = [10, 20, 30];
const discounted = prices.map((price) => {
return price * 0.9;
});
console.log(prices); // [10, 20, 30]
console.log(discounted); // [9, 18, 27]This is one reason map is so useful.
It lets you create transformed data without damaging the original data.
Transforming Strings
map can transform strings too.
const names = ["ava", "noah", "mira"];
const upperNames = names.map((name) => {
return name.toUpperCase();
});
console.log(upperNames); // ["AVA", "NOAH", "MIRA"]The original array is unchanged:
console.log(names); // ["ava", "noah", "mira"]Extracting Object Properties
One of the most common uses of map is extracting one property from each object.
const users = [
{ id: 1, name: "Alice", role: "admin" },
{ id: 2, name: "Bob", role: "user" },
{ id: 3, name: "Charlie", role: "user" },
];
const userNames = users.map((user) => {
return user.name;
});
console.log(userNames); // ["Alice", "Bob", "Charlie"]Shorter version:
const userNames = users.map((user) => user.name);This is common when working with API data.
You may receive a large array of objects, but only need one field from each object.
Transforming Objects
You can also use map to create a new array of modified objects.
const products = [
{ name: "Keyboard", price: 50 },
{ name: "Mouse", price: 25 },
{ name: "Monitor", price: 200 },
];
const productsWithTax = products.map((product) => {
return {
name: product.name,
price: product.price,
priceWithTax: product.price * 1.08,
};
});
console.log(productsWithTax);Each original product becomes a new object in the returned array.
You can also use object spread to keep existing properties:
const productsWithTax = products.map((product) => {
return {
...product,
priceWithTax: product.price * 1.08,
};
});This creates new objects.
It does not mutate the original objects directly.
Returning Object Literals With Arrow Functions
There is one syntax detail to know.
If you want to implicitly return an object literal from an arrow function, wrap the object in parentheses.
const users = ["Alice", "Bob"];
const userObjects = users.map((name) => ({
name,
active: true,
}));
console.log(userObjects);Without parentheses, JavaScript may treat {} as the function body instead of an object.
This is wrong:
const userObjects = users.map((name) => {
name,
active: true,
});Use either an explicit return:
const userObjects = users.map((name) => {
return {
name,
active: true,
};
});Or an implicit return with parentheses:
const userObjects = users.map((name) => ({
name,
active: true,
}));Using the Index
The second callback argument is the index.
const tasks = ["Install dependencies", "Run tests", "Deploy"];
const numberedTasks = tasks.map((task, index) => {
return `${index + 1}. ${task}`;
});
console.log(numberedTasks);Output:
[
"1. Install dependencies",
"2. Run tests",
"3. Deploy"
]The index starts at 0, so index + 1 gives a human-friendly number.
Changing Data Types
map can convert values from one type to another.
const stringNumbers = ["10", "20", "30"];
const numbers = stringNumbers.map((value) => {
return Number(value);
});
console.log(numbers); // [10, 20, 30]Shorter version:
const numbers = stringNumbers.map(Number);This works because Number is a function.
map calls it for each item.
Be Careful With parseInt
You might think this works:
const values = ["10", "20", "30"];
const numbers = values.map(parseInt);
console.log(numbers);But this can produce surprising results.
Why?
map passes more than one argument to the callback:
currentValue, index, arrayparseInt accepts a second argument called the radix.
So the index gets passed as the radix.
Use this instead:
const numbers = values.map((value) => parseInt(value, 10));
console.log(numbers); // [10, 20, 30]Or use Number when simple conversion is enough:
const numbers = values.map(Number);Generating UI Data
In frontend development, map is often used to generate UI elements from data.
Here is a simple HTML string example:
const items = ["Milk", "Eggs", "Bread"];
const htmlItems = items.map((item) => {
return `<li>${item}</li>`;
});
console.log(htmlItems);Output:
["<li>Milk</li>", "<li>Eggs</li>", "<li>Bread</li>"]You can join them into one string:
const html = htmlItems.join("");
console.log(html); // <li>Milk</li><li>Eggs</li><li>Bread</li>Frameworks like React use this same idea to render lists from arrays of data.
Forgetting to Return
This is the classic map mistake.
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => {
number * 2;
});
console.log(doubled); // [undefined, undefined, undefined]The callback uses curly braces, but it does not return anything.
So each callback call returns undefined.
map builds a new array from those returned values.
Correct version:
const doubled = numbers.map((number) => {
return number * 2;
});Or:
const doubled = numbers.map((number) => number * 2);map Always Returns the Same Length
map returns a new array with the same number of elements as the original.
const numbers = [1, 2, 3];
const result = numbers.map((number) => {
if (number > 1) {
return number;
}
});
console.log(result); // [undefined, 2, 3]The first item did not return a value, so it became undefined.
map did not remove it.
If you want to remove items, use filter.
const result = numbers.filter((number) => {
return number > 1;
});
console.log(result); // [2, 3]You will learn filter in the next lesson.
map vs forEach
forEach is for doing side effects.
map is for transforming data into a new array.
| Feature | forEach |
map |
|---|---|---|
| Main purpose | Run side effects | Transform each item |
| Return value | undefined |
A new array |
| Callback return needed? | No | Yes |
| New array length | No new array | Same length as original |
| Best for | Logging, DOM updates, external actions | Creating transformed arrays |
Example with forEach:
const numbers = [1, 2, 3];
numbers.forEach((number) => {
console.log(number * 2);
});Example with map:
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => {
return number * 2;
});
console.log(doubled); // [2, 4, 6]If you need the transformed values later, use map.
map and Mutation
map itself returns a new array and does not mutate the original array.
But you can still write a callback that mutates objects inside the array.
const users = [
{ name: "Alice", active: false },
{ name: "Bob", active: false },
];
const result = users.map((user) => {
user.active = true;
return user;
});
console.log(users[0].active); // trueThis mutates the original objects because objects are reference values.
A safer approach is to return new objects:
const result = users.map((user) => {
return {
...user,
active: true,
};
});
console.log(users[0].active); // false
console.log(result[0].active); // trueThis pattern is common in modern JavaScript.
Best Practices
Use map when you want a new array:
const doubled = numbers.map((number) => number * 2);Always return a value from the callback:
const names = users.map((user) => {
return user.name;
});Use concise arrow functions for simple transformations:
const names = users.map((user) => user.name);Use explicit returns for multi-line transformations:
const summaries = users.map((user) => {
const label = `${user.name} (${user.role})`;
return label;
});Avoid mutating objects inside map unless that is truly intended:
const updatedUsers = users.map((user) => ({
...user,
active: true,
}));Use filter if your goal is to remove items:
const adults = users.filter((user) => user.age >= 18);Common Mistakes
Mistake 1: Forgetting return
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => {
number * 2;
});
console.log(doubled); // [undefined, undefined, undefined]Correct:
const doubled = numbers.map((number) => {
return number * 2;
});Mistake 2: Using map for Side Effects Only
const names = ["Ava", "Noah"];
names.map((name) => {
console.log(name);
});This creates a new array that you ignore.
Use forEach for side effects:
names.forEach((name) => {
console.log(name);
});Mistake 3: Expecting map to Filter Items
const numbers = [1, 2, 3];
const result = numbers.map((number) => {
if (number > 1) {
return number;
}
});
console.log(result); // [undefined, 2, 3]Use filter to remove items:
const result = numbers.filter((number) => number > 1);
console.log(result); // [2, 3]Mistake 4: Accidentally Returning an Object Incorrectly
const names = ["Ava", "Noah"];
const users = names.map((name) => {
name: name;
});
console.log(users); // [undefined, undefined]Use parentheses for an implicit object return:
const users = names.map((name) => ({
name: name,
}));Or use an explicit return:
const users = names.map((name) => {
return {
name: name,
};
});Quick Check
What does this return?
const numbers = [2, 4, 6];
const result = numbers.map((number) => number + 1);It returns:
[3, 5, 7]What does this return?
const numbers = [1, 2, 3];
const result = numbers.map((number) => {
number * 2;
});It returns:
[undefined, undefined, undefined]The callback does not explicitly return a value.
What should you use if you want to remove items from an array?
Use filter, not map.
const numbers = [1, 2, 3];
const greaterThanOne = numbers.filter((number) => number > 1);
console.log(greaterThanOne); // [2, 3]Summary
map transforms every element in an array and returns a new array.
- Use
mapwhen you want a transformed array. - The original array is not changed by
mapitself. - The callback receives
currentValue,index, and the original array. - The callback's return value becomes the new array element.
- The new array has the same length as the original.
- Forgetting
returngives youundefinedvalues. - Use
forEachfor side effects. - Use
filterwhen you want to remove items. - Be careful not to mutate objects inside
mapunless you intend to.