What you'll learn
- Quick answer
- The Big Picture: Three Tools, Three Jobs
- map(): Transform Every Item
- filter(): Keep Only What You Want
- reduce(): Boil It Down to One Value
- Chaining Them Together: filter → map → reduce
- Common Mistakes (and How to Avoid Them)
- Quick Cheat Sheet: When to Use Which
- Practice and Next Steps
- FAQ
Quick Answer
In JavaScript, map, filter and reduce are three array methods that help you work with lists without writing loops by hand. Use map to transform every item into a new value, filter to keep only the items that pass a test, and reduce to combine all items into a single result like a sum or total. All three return a new value instead of changing the original array, which keeps your code clean and predictable. Once you learn them, you can chain them together — filter, then map, then reduce — to solve real problems in a readable way.
The Big Picture: Three Tools, Three Jobs
If you have written a few for loops in JavaScript, you already know the pain: loop counters, temporary arrays, and off-by-one bugs. The good news is that JavaScript gives you three built-in array methods that handle the most common list jobs for you. This guide to javascript map filter reduce shows you exactly what each one does, with short runnable examples you can paste straight into your browser console.
Here is the one-line summary, and it is worth memorising:
- map — transform every item into a new item (same number of items out).
- filter — select the items that pass a test (fewer or equal items out).
- reduce — accumulate all items into a single value (one thing out).
All three are methods on arrays, all three take a callback function, and — this is the important part — none of them change the original array. They return a brand new value instead. If you want a full, structured path from the basics to this kind of modern JavaScript, our free JavaScript course walks through arrays step by step.
map(): Transform Every Item
Syntax
const newArray = oldArray.map((item) => {
return /* the transformed item */;
});The callback runs once for every item. Whatever you return becomes the matching item in the new array. Because input and output line up one-to-one, a map result always has the same length as the original.
Example: double every number
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((n) => n * 2);
console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4] — unchangedThe arrow function (n) => n * 2 has no curly braces, so its value is returned automatically. This is called an implicit return, and it is very common with map.
Example: pull one field out of a list of objects
const students = [
{ name: "Aarav", city: "Pune" },
{ name: "Diya", city: "Kochi" }
];
const names = students.map((student) => student.name);
console.log(names); // ["Aarav", "Diya"]This "grab one property from each object" pattern is everywhere in real apps — it is exactly how you turn a list of records into a list of labels for a dropdown or an on-screen list.
filter(): Keep Only What You Want
Syntax
const newArray = oldArray.filter((item) => {
return /* true to keep, false to drop */;
});The callback must return a boolean (or something truthy/falsy). If it returns true, the item is kept; if false, it is left out. The result is a new array that is the same length or shorter — never longer.
Example: keep only the passing scores
const scores = [45, 82, 33, 91, 58];
const passed = scores.filter((score) => score >= 50);
console.log(passed); // [82, 91, 58]Notice that filter does not change the values — it only decides which ones survive. If you need to keep some items and change them, that is a job for filter followed by map, which we do below.
A common trap
Make sure your callback actually returns a condition. score >= 50 returns true or false, which is what filter needs. Returning a number or a string by mistake can quietly keep items you meant to drop, because non-empty strings and non-zero numbers are "truthy".
reduce(): Boil It Down to One Value
Syntax
const result = array.reduce((accumulator, current) => {
return /* the new accumulator */;
}, initialValue);reduce is the most powerful of the three and the one beginners find trickiest. It walks through the array carrying a running value called the accumulator. On each step you return the updated accumulator, and whatever you return is passed into the next step. The second argument, initialValue, is where the accumulator starts.
Example: add up a list of numbers
const numbers = [10, 20, 30, 40];
const total = numbers.reduce((sum, current) => {
return sum + current;
}, 0);
console.log(total); // 100Step by step: the accumulator sum starts at 0. Then 0 + 10 = 10, 10 + 20 = 30, 30 + 30 = 60, and finally 60 + 40 = 100. One array went in, one number came out.
Always pass the initial value. If you skip the 0, reduce uses the first array item as the starting accumulator, which usually still works for a sum but throws a TypeError on an empty array. Passing 0 (or [], or {} depending on what you are building) makes your code both safe and clear.
Chaining Them Together: filter → map → reduce
Because map and filter each return a new array, you can call the next method straight onto the result. This is called chaining, and the classic combo is filter → map → reduce: narrow the list down, reshape what is left, then boil it to one value.
Say we have a shopping cart and we want the total price of only the in-stock items:
const cart = [
{ item: "Notebook", price: 60, inStock: true },
{ item: "Pen", price: 15, inStock: false },
{ item: "Backpack", price: 800, inStock: true },
{ item: "Eraser", price: 10, inStock: true }
];
const total = cart
.filter((product) => product.inStock) // keep in-stock items
.map((product) => product.price) // turn them into prices
.reduce((sum, price) => sum + price, 0); // add the prices up
console.log(total); // 870Read it top to bottom like a sentence: from the cart, keep the in-stock products, take their prices, and add them together. The out-of-stock Pen is dropped by filter, so the total is 60 + 800 + 10 = 870. Compare that to a hand-written loop with an if and a running total — the chained version says what you want, not the bookkeeping of how.
One practical note: each step creates a new array, so for very large lists in performance-critical code you might do the whole job in a single reduce or a plain loop. For everyday app code, readable chaining is the right default.
Common Mistakes (and How to Avoid Them)
1. Forgetting to return inside curly braces
When your callback uses { }, you must write return yourself. Forgetting it is the number-one beginner bug:
// Wrong — nothing is returned, so every item becomes undefined
const doubled = [1, 2, 3].map((n) => {
n * 2;
});
console.log(doubled); // [undefined, undefined, undefined]
// Right — add return, or drop the braces for an implicit return
const fixed = [1, 2, 3].map((n) => n * 2);
console.log(fixed); // [2, 4, 6]2. Mutating the original data
map gives you a new array, but if the items are objects they are still references to the originals. Changing a property inside the callback changes the source too:
const students = [
{ name: "Aarav", age: 20 },
{ name: "Diya", age: 19 }
];
// Risky — this edits the original student objects
const older = students.map((student) => {
student.age = student.age + 1; // mutation!
return student;
});
// Safer — build a fresh object with the spread operator
const olderSafe = students.map((student) => ({
...student,
age: student.age + 1
}));Keeping these methods "pure" — no changes to the inputs — is what makes them predictable and easy to debug.
3. Using map when you mean forEach
If you are not using the array that map returns — say you only want to console.log each item — use forEach instead. Using map just for its side effects wastes a new array and confuses readers about your intent.
Quick Cheat Sheet: When to Use Which
Here is a quick reference you can come back to:
| Method | Job | Callback returns | Result |
|---|---|---|---|
| map | Transform each item | The new item | New array, same length |
| filter | Select items | true or false | New array, same or shorter |
| reduce | Combine into one value | The new accumulator | Any single value |
A simple way to choose: if you want the same number of items but changed, reach for map. If you want fewer items, reach for filter. If you want one answer built from the whole list — a sum, an average, a grouped object — reach for reduce.
These three methods are the backbone of everyday JavaScript and show up constantly in frameworks like React, where you will map a list of data into a list of UI elements almost every day. They are well worth practising until they feel natural.
Practice and Next Steps
You do not need to memorise everything at once. Start with map and filter, since they read almost like English, and come back to reduce once those feel comfortable. The fastest way to learn is to open your browser console right now and retype each example above, changing the numbers to see what happens.
A good practice set: given an array of student objects, (1) map to a list of names, (2) filter the ones who scored above 50, and (3) reduce to their average score. If you can do those three, you understand the pattern.
When you are ready to go deeper — arrays, objects, async code, and building real projects — our free, beginner-friendly JavaScript course takes you there in order, with no prior experience assumed.
Frequently Asked Questions
What is the difference between map and forEach?
map returns a new array built from whatever you return in the callback, so use it when you want a transformed list. forEach returns undefined and is for side effects like logging — it does not build a new array.
Do map, filter or reduce change the original array?
No. All three return a new value and leave the original array untouched. The only way they affect the original is if your callback mutates the objects inside it, so avoid editing items in place.
Why is my map result full of undefined?
You almost certainly forgot to return inside a callback that uses curly braces. Either add an explicit return, or remove the braces so the arrow function returns its value automatically.
Should I always pass an initial value to reduce?
Yes, it is the safe habit. Without an initial value, reduce uses the first item as the starting accumulator and throws an error on an empty array. Passing a starting value like 0 or [] keeps it predictable.
Can I use these methods on objects?
Not directly — map, filter and reduce are array methods. To use them on an object, first convert it with Object.keys(), Object.values() or Object.entries(), which return arrays you can then map, filter or reduce.
Are these methods slower than a for loop?
Slightly, and each chained step creates a new array, but for almost all everyday code the difference is tiny and not worth worrying about. Choose readability first, and only reach for a plain loop when profiling shows a real hot spot.
