Array Methods: map, filter, and reduce Get Certified
Three of the most useful array methods in modern JavaScript are
map(), filter(), and
reduce(). They let you transform, select, and
combine the values in an array without writing long loops by hand.
In this lesson you will learn what each method does, how they differ, and how to chain them together for clear, readable data processing.
map(): Transforming Every Element
map() creates a new array by calling a function on
every element of the original array. The original array is never
modified.
What this code does: map multiplies every price by 1.1 and returns a new array.
The original prices array stays unchanged.
const prices = [10, 25, 40];
const inflated = prices.map(function (price) {
return price * 1.1;
});
console.log(inflated);
console.log(prices); // original unchanged
const prices = [10, 25, 40]; creates the original list of prices.const inflated = prices.map(function (price) { starts a transformation. For each element the callback receives the current value as price.return price * 1.1; multiplies the price by 1.1 and returns the result. That returned value becomes the corresponding element in the new array.}); closes the callback and the map call. The new array is stored in inflated.console.log(inflated); prints the new array of inflated prices.console.log(prices); // original unchanged confirms that map never modified the source array.
What this code does: Arrow-function form of map. Each product name is converted to uppercase.
const products = ["laptop", "phone", "tablet"];
const uppercased = products.map(name => name.toUpperCase());
console.log(uppercased);
const products = ["laptop", "phone", "tablet"];const uppercased = products.map(name => name.toUpperCase()); uses the concise arrow syntax. Each name is converted to uppercase and collected into a new array.console.log(uppercased); prints ["LAPTOP", "PHONE", "TABLET"].filter(): Keeping Only What Matches
filter() builds a new array that contains only the
elements for which the callback returns a truthy value.
What this code does: filter keeps only the scores that are 50 or higher.
const scores = [42, 88, 55, 91, 33];
const passing = scores.filter(function (score) {
return score >= 50;
});
console.log(passing);
const scores = [42, 88, 55, 91, 33];const passing = scores.filter(function (score) { starts selecting elements.return score >= 50; returns true only for scores that meet the threshold. Those elements are kept.}); closes the callback. The new array contains only the passing scores.console.log(passing); prints [88, 55, 91].What this code does: Filter an array of objects, keeping only the items that are in stock.
const inventory = [
{ name: "Keyboard", inStock: true },
{ name: "Mouse", inStock: false },
{ name: "Monitor", inStock: true }
];
const available = inventory.filter(item => item.inStock);
console.log(available);
const inventory = [{ name: "Keyboard", inStock: true },{ name: "Mouse", inStock: false },{ name: "Monitor", inStock: true }];const available = inventory.filter(item => item.inStock); keeps only the objects whose inStock property is true.console.log(available); prints the two in-stock items.Combining map() and filter()
You can chain filter() and map() to first
select the elements you care about and then transform them.
What this code does: First keep only items priced above 10, then extract just their names.
const items = [
{ name: "Pen", price: 2 },
{ name: "Notebook", price: 12 },
{ name: "Backpack", price: 45 },
{ name: "Eraser", price: 1 }
];
const expensiveNames = items
.filter(item => item.price > 10)
.map(item => item.name);
console.log(expensiveNames);
const items = [{ name: "Pen", price: 2 },{ name: "Notebook", price: 12 },{ name: "Backpack", price: 45 },{ name: "Eraser", price: 1 }];const expensiveNames = items.filter(item => item.price > 10) keeps only the items whose price is greater than 10..map(item => item.name); turns the remaining objects into an array of name strings.console.log(expensiveNames); prints ["Notebook", "Backpack"].reduce(): Combining Everything Into One Value
reduce() walks through an array and builds a single
result (a number, an object, another array, etc.) by repeatedly
applying a callback that receives an accumulator and the current
element.
What this code does: reduce adds every expense together, starting from an initial value of 0.
const expenses = [45.5, 12.99, 89.0, 6.25];
const totalSpent = expenses.reduce(function (accumulator, amount) {
return accumulator + amount;
}, 0);
console.log(totalSpent);
const expenses = [45.5, 12.99, 89.0, 6.25];const totalSpent = expenses.reduce(function (accumulator, amount) { starts the reduction. The second argument 0 is the initial value of the accumulator.return accumulator + amount; returns the new accumulator value after adding the current element.}, 0); closes the callback and supplies the starting value of 0.console.log(totalSpent); prints the sum of all expenses.Using reduce() to Find a Maximum
Because the accumulator can hold any value, reduce()
can also be used to find the highest-rated item, the longest
string, and so on.
What this code does: Walk through the books and keep the one with the highest rating.
const books = [
{ title: "Dune", rating: 4.8 },
{ title: "Circe", rating: 4.6 },
{ title: "Educated", rating: 4.7 }
];
const topRatedBook = books.reduce(function (best, current) {
return current.rating > best.rating ? current : best;
});
console.log(topRatedBook);
const books = [{ title: "Dune", rating: 4.8 },{ title: "Circe", rating: 4.6 },{ title: "Educated", rating: 4.7 }];const topRatedBook = books.reduce(function (best, current) { starts with the first book as the initial accumulator (no explicit initial value is supplied).return current.rating > best.rating ? current : best; compares the current book with the best-so-far and returns the one with the higher rating.});console.log(topRatedBook); prints the book object with the highest rating (Dune).Using reduce() to Build an Object
A common pattern is to start with an empty object and use
reduce() to count how many times each value appears.
What this code does: Count how many times each order item appears, building a frequency object.
const orders = ["pizza", "salad", "pizza", "soup", "pizza", "salad"];
const orderCounts = orders.reduce(function (counts, item) {
counts[item] = (counts[item] || 0) + 1;
return counts;
}, {});
console.log(orderCounts);
const orders = ["pizza", "salad", "pizza", "soup", "pizza", "salad"];const orderCounts = orders.reduce(function (counts, item) { the initial value is {}.counts[item] = (counts[item] || 0) + 1; if the key does not yet exist it is treated as 0, then 1 is added.return counts; the updated object is passed to the next iteration.}, {});console.log(orderCounts); prints an object such as { pizza: 3, salad: 2, soup: 1 }.Chaining map(), filter(), and reduce()
The three methods can be chained so that each step does one clear job: select, transform, then combine.
What this code does: Keep only affordable items, compute each line-item total, then sum those totals.
const cartItems = [
{ name: "Notebook", price: 4.5, quantity: 3 },
{ name: "Desk Lamp", price: 22.0, quantity: 1 },
{ name: "Pen Set", price: 8.0, quantity: 2 },
{ name: "Monitor Stand", price: 35.0, quantity: 1 }
];
const totalForAffordableItems = cartItems
.filter(item => item.price < 25)
.map(item => item.price * item.quantity)
.reduce((sum, subtotal) => sum + subtotal, 0);
console.log(totalForAffordableItems);
const cartItems = [{ name: "Notebook", price: 4.5, quantity: 3 },{ name: "Desk Lamp", price: 22.0, quantity: 1 },{ name: "Pen Set", price: 8.0, quantity: 2 },{ name: "Monitor Stand", price: 35.0, quantity: 1 }];const totalForAffordableItems = cartItems.filter(item => item.price < 25) keeps items whose unit price is less than 25..map(item => item.price * item.quantity) multiplies price by quantity for each remaining item..reduce((sum, subtotal) => sum + subtotal, 0); adds those subtotals together, starting from 0.console.log(totalForAffordableItems); prints the combined cost of the affordable items.When a Regular Loop Might Be Better
Sometimes a plain for loop is clearer, especially
when you need to stop as soon as a match is found.
What this code does: A regular loop finds the first item priced above 20 and then stops. This is more efficient than filtering the whole array when only the first match is needed.
const cartItems = [
{ name: "Notebook", price: 4.5 },
{ name: "Desk Lamp", price: 22.0 },
{ name: "Monitor Stand", price: 35.0 }
];
// A regular loop makes sense here since we want to stop early.
let firstExpensiveItem = null;
for (let i = 0; i < cartItems.length; i++) {
if (cartItems[i].price > 20) {
firstExpensiveItem = cartItems[i];
break;
}
}
console.log(firstExpensiveItem);
const cartItems = [{ name: "Notebook", price: 4.5 },{ name: "Desk Lamp", price: 22.0 },{ name: "Monitor Stand", price: 35.0 }];// A regular loop makes sense here since we want to stop early.let firstExpensiveItem = null;for (let i = 0; i < cartItems.length; i++) {if (cartItems[i].price > 20) {firstExpensiveItem = cartItems[i];break; exits the loop as soon as the first match is found.}}console.log(firstExpensiveItem); prints the Desk Lamp object.map() vs. filter() vs. reduce()
| Method | Returns | Typical Use |
|---|---|---|
| map() | A new array, same length | Transform each element |
| filter() | A new array, same length or shorter | Keep only elements that match a condition |
| reduce() | A single value (any type) | Combine all elements into one result |
Practical Example
Let's calculate an average product rating using
filter(), map(), and
reduce() together.
What this code does: Filter verified reviews, map to their star ratings, then reduce to a total. Chaining keeps each step focused and readable.
const reviews = [
{ product: "Headphones", stars: 5, verified: true },
{ product: "Headphones", stars: 2, verified: false },
{ product: "Headphones", stars: 4, verified: true },
{ product: "Headphones", stars: 5, verified: true }
];
const verifiedStars = reviews
.filter(review => review.verified)
.map(review => review.stars);
const averageRating = verifiedStars.reduce((sum, stars) => sum + stars, 0) / verifiedStars.length;
console.log("Average rating from verified reviews:", averageRating.toFixed(1));
const reviews = [{ product: "Headphones", stars: 5, verified: true },{ product: "Headphones", stars: 2, verified: false },{ product: "Headphones", stars: 4, verified: true },{ product: "Headphones", stars: 5, verified: true }];const verifiedStars = reviews.filter(review => review.verified).map(review => review.stars); produces an array of numbers such as [5, 4, 5].const averageRating = verifiedStars.reduce((sum, stars) => sum + stars, 0) / verifiedStars.length; sums the stars and divides by how many there are.console.log("Average rating from verified reviews:", averageRating.toFixed(1)); prints the average rounded to one decimal place.Common Mistakes With map, filter, and reduce
- Forgetting to
returna value from the callback passed tomap(), resulting in an array full ofundefined. - Using
map()whenforEach()would be more appropriate, because the new array it returns is never used. - Forgetting the initial value in
reduce(), causing unexpected behavior on an empty array. - Using
filter()just to find one matching element, whenfind()would stop searching immediately after a match instead of checking every element. - Chaining so many methods together that the resulting one-liner becomes harder to read than a few clearly named steps.
Best Practices for map, filter, and reduce
- Use
map()only when you need the transformed array itself — useforEach()for side effects like logging. - Always provide an initial value to
reduce()when working with sums, counts, or objects. - Break especially long chains into intermediate variables with descriptive names, to keep the logic easy to follow.
- Reach for more specific methods like
find()orsome()when they match your intent more precisely thanfilter(). - Keep callback functions small and focused on a single transformation or condition.
Quick Summary
map()transforms every element into a new array of the same length.filter()keeps only the elements that pass a given test.reduce()combines all elements into a single result, using an accumulator.- These methods can be chained together to express multi-step data processing clearly.
- None of the three modify the original array — they all return new values.
- A regular loop (or a more specific method like
find()) is sometimes a better fit than forcing everything into these three methods.
Try It Yourself
Modify the code below. Try changing the filter condition, or adding another step to the chain.
What this code does: Practice example: filter passing students, extract grades, then average them. Try changing the cutoff or adding another step, then click Test My Code.
const students = [
{ name: "Noah", grade: 78 },
{ name: "Aisha", grade: 92 },
{ name: "Liam", grade: 65 },
{ name: "Zara", grade: 88 }
];
const passingAverage = students
.filter(student => student.grade >= 70)
.map(student => student.grade)
.reduce((sum, grade, index, array) => {
sum += grade;
if (index === array.length - 1) {
return sum / array.length;
}
return sum;
}, 0);
console.log("Average passing grade:", passingAverage);
const students = [{ name: "Noah", grade: 78 },{ name: "Aisha", grade: 92 },{ name: "Liam", grade: 65 },{ name: "Zara", grade: 88 }];const passingAverage = students.filter(student => student.grade >= 70).map(student => student.grade).reduce((sum, grade, index, array) => { receives the running sum, the current grade, the current index, and the whole array.sum += grade;if (index === array.length - 1) {return sum / array.length;}return sum;}, 0);console.log("Average passing grade:", passingAverage); prints the average of the grades that were 70 or higher.Tip: A useful way to decide between these methods: ask "do I want the same number of items back, transformed?" (map), "do I want fewer items back?" (filter), or "do I want just one final answer?" (reduce).
Understanding map(), filter(), and
reduce() is essential before moving on to other array
methods like find(), some(), and
every(), and more advanced JavaScript concepts.
🧪 Test Your JavaScript Code
Edit the code on the left and click "Run Code" to see the console output on the right.
Click "Run Code" to see the output here.
Code Explanation
The complete example stays visible. Use Previous and Next to move through its logical blocks.
Select Next to begin exploring the code.