JavaScript Array Methods: map, filter, reduce and More With Examples
Stop writing the same loops. Learn the array methods you will use every day on one realistic list of orders, see real output for each, and avoid the traps that catch even experienced developers.
maptransforms every item,filterkeeps some items, andreducecombines items into one result.- These three return new values and leave the original array unchanged.
sortchanges the original array and compares values as strings by default.- Always pass a starting value to
reduce, or an empty array throws aTypeError.
Once you know the core JavaScript array methods, most data work becomes a short, readable line rather than a loop with a counter and a temporary variable. They appear everywhere: in React components, API handling and Node scripts alike.
To keep things practical, we use one list of orders throughout, so you can see how methods work together. We ran all of this on Node.js 24, and the outputs shown are from that run. Newer methods such as Object.groupBy need a recent browser or runtime, as noted below.
JavaScript array methods cheat sheet
| Method | Returns | Changes original? | Use it to |
|---|---|---|---|
map |
New array, same length | No | Transform each item |
filter |
New array, same or shorter | No | Keep matching items |
reduce |
Any single value | No | Sum, count or build objects |
find |
First match or undefined |
No | Get one item |
findIndex |
Position or -1 | No | Locate one item |
some |
Boolean | No | Check if any item matches |
every |
Boolean | No | Check if all items match |
sort |
The same array | Yes | Order items in place |
toSorted |
New array | No | Order items safely |
flatMap |
New array | No | Map, then flatten one level |
The sample data
const orders = [
{ id: 1, customer: "Asha", total: 1200, status: "paid" },
{ id: 2, customer: "Ben", total: 300, status: "pending" },
{ id: 3, customer: "Asha", total: 800, status: "paid" },
{ id: 4, customer: "Chitra", total: 2500, status: "paid" },
{ id: 5, customer: "Dev", total: 150, status: "cancelled" },
];
map: transform every item
map calls your function once for each item and collects the return values into a new array. The result always has the same length as the original.
orders.map((o) => o.total);
// [ 1200, 300, 800, 2500, 150 ]
Compare that with the loop it replaces:
const totals = [];
for (const o of orders) {
totals.push(o.total);
}
The result is identical, but map states the intent straight away, and there is no temporary array to manage. The callback also receives the index as a second argument, and the whole array as a third. That detail causes a famous bug, covered in the mistakes section below.
filter: keep what matches
filter keeps each item for which your function returns a truthy value:
orders.filter((o) => o.status === "paid").map((o) => o.id);
// [ 1, 3, 4 ]
If nothing matches, you get an empty array rather than an error, so code that follows can safely loop over the result.
reduce: combine into one value
reduce confuses people the most, but the idea is simple. It walks through the array carrying a running result, called the accumulator. Your function receives the accumulator and the current item, and returns the next accumulator.
orders.reduce((sum, o) => sum + o.total, 0);
// 4950
Here is how the running value changes on each step:
| Step | sum before |
o.total |
sum after |
|---|---|---|---|
| 1 | 0 | 1200 | 1200 |
| 2 | 1200 | 300 | 1500 |
| 3 | 1500 | 800 | 2300 |
| 4 | 2300 | 2500 | 4800 |
| 5 | 4800 | 150 | 4950 |
The accumulator can be any type, not just a number. Start with an empty object, and you can total spending per customer:
const byCustomer = orders.reduce((acc, o) => {
acc[o.customer] = (acc[o.customer] ?? 0) + o.total;
return acc;
}, {});
// { Asha: 2000, Ben: 300, Chitra: 2500, Dev: 150 }
Do not forget that return acc. Whatever your function returns becomes the accumulator on the next step, so leaving it out breaks the next iteration.
Chaining methods
Because map and filter return arrays, you can chain them into a readable pipeline. This finds total revenue from paid orders:
const paidTotal = orders
.filter((o) => o.status === "paid")
.map((o) => o.total)
.reduce((sum, t) => sum + t, 0);
// 4500
Filter first, so later steps do less work. Each step creates a new array, which is rarely a problem with ordinary data. If you have a measured performance issue with very large arrays, a single reduce or plain loop can do the same job with fewer allocations. Prefer clarity until you have measured a real problem.
find, some and every
These methods stop as soon as they know the answer, so they are more efficient than filter when you only need one item or a yes or no.
orders.find((o) => o.total > 1000).id; // 1
orders.findIndex((o) => o.id === 3); // 2
orders.some((o) => o.status === "cancelled"); // true
orders.every((o) => o.total > 100); // true
Remember that find returns undefined when nothing matches, so .id on that result would throw. Write orders.find(...)?.id if a match is not guaranteed. To check for a simple value in a list of strings or numbers, includes is shorter: ["paid", "pending"].includes(status).
Tip: If you only need the first match, use find instead of filter(...)[0]. It reads better and stops at the first hit rather than scanning the whole array.
sort and toSorted
sort has two surprises. By default it compares values as strings, and it changes the original array.
[10, 9, 1].sort(); // [ 1, 10, 9 ]
[10, 9, 1].sort((a, b) => a - b); // [ 1, 9, 10 ]
As strings, "10" comes before "9", which gives that odd first result. Always pass a compare function for numbers. It should return a negative number if a comes first, or a positive number if b does.
When you need to keep the original order, use toSorted, which returns a new array:
const nums = [3, 1, 2];
nums.toSorted((a, b) => a - b); // [ 1, 2, 3 ]
nums; // [ 3, 1, 2 ]
This is particularly useful in React, where you should not mutate state directly. For older environments, [...nums].sort() achieves the same thing.
flatMap and groupBy
flatMap maps each item and flattens the result by one level, which is handy when one input produces several outputs:
["a b", "c"].flatMap((s) => s.split(" "));
// [ 'a', 'b', 'c' ]
Object.groupBy is a newer built-in that replaces a common reduce pattern. It groups items by a key you return:
const groups = Object.groupBy(orders, (o) => o.status);
Object.keys(groups);
// [ 'paid', 'pending', 'cancelled' ]
It works in current browsers and Node.js 21 or later. Check your support targets before you rely on it.
forEach vs for…of
forEach runs a function for each item but returns nothing, so it suits side effects such as logging. There are two limits to know about: you cannot break out early, and it does not wait for asynchronous callbacks. For sequential async work, use for...of:
for (const order of orders) {
await saveOrder(order);
}
That runs one at a time. To run them in parallel, use await Promise.all(orders.map(saveOrder)). Our JavaScript async/await guide explains the difference in detail. Callbacks in all these methods are also closures, as explained in JavaScript closures, which is why they can read variables from the surrounding scope.
Common mistakes
Passing parseInt straight to map
["1", "2", "10"].map(parseInt); // [ 1, NaN, 2 ]
["1", "2", "10"].map(Number); // [ 1, 2, 10 ]
map passes the item and its index, and parseInt treats that second argument as the number base. So it evaluates parseInt("2", 1), which gives NaN. Use Number or write (s) => parseInt(s, 10).
Calling reduce without a starting value
[].reduce((a, b) => a + b);
// TypeError: Reduce of empty array with no initial value
An API can easily return an empty list, so always provide the initial value.
Forgetting to return from a block
With curly braces, an arrow function needs an explicit return. Writing orders.map((o) => { o.total; }) gives you an array of undefined. Remove the braces or add return.
Mutating objects inside map
map creates a new array, but the objects inside are still the same ones. Writing o.total = 0 in the callback changes your original data. Return a copy instead: orders.map((o) => ({ ...o, total: 0 })).
Final thoughts
Learn map, filter and reduce first, then add find, some and toSorted. Together, they cover most of your day-to-day data handling. To practise, take any loop in your current project and try rewriting it. If the new version reads more clearly, keep it. If it does not, the loop was fine.
Frequently asked questions
What is the difference between map and filter?
map returns a new array of the same length with each item transformed. filter returns a new array containing only the items that pass your test.
What is the difference between map and forEach?
map returns a new array built from your callback’s return values. forEach returns nothing, so use it only for side effects such as logging.
Does map change the original array?
No, it returns a new array. However, if your callback modifies an object inside the array, that original object does change, so return a copy instead.
When should I use reduce?
Use reduce to combine items into one result, such as a total or a lookup object. If a simple map or filter does the job, prefer those for readability.
Why does sort put 10 before 9?
By default, sort compares values as strings, and “10” comes before “9” alphabetically. Pass a compare function such as (a, b) => a – b for numbers.
Keep learning
Need help with testing, WordPress or SEO?
We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.