Skip to Content
JavaScript Intermediate: Write Code That Doesn't Fall Apart When the Data Changes
Intermediate
0 likes
Courses
JavaScript Intermediate: Write Code That Doesn't Fall Apart When the Data Changes

Array Methods: map, filter, reduce and When a Loop Is Clearer

Use map, filter and reduce on a list of orders, plus find, some and toSorted, and know when a for...of loop reads better. After this, you can answer report questions in a few clear lines.

Course content

Sign in to save your progress.

Course Home

Skip ahead: If you already chain filter and map and know when reduce is a bad idea, skip to "When a loop is clearer".

Most real data in JavaScript is a list of objects: orders, products, users. Most of what you do with it is one of three things: change every item into something else, keep only some items, or boil the whole list down to one value. map, filter and reduce are those three things. They don't do anything a for...of loop can't. They just say what you're doing in the name, which makes code easier to read, until you overuse them.

Every example here uses this list:

const orders = [
  { id: 1, customer: "Ana", status: "paid", total: 1200 },
  { id: 2, customer: "Ben", status: "pending", total: 450 },
  { id: 3, customer: "Ana", status: "paid", total: 300 },
  { id: 4, customer: "Cris", status: "cancelled", total: 900 },
];

map: one new item for every item

const labels = orders.map(order => `#${order.id} ${order.customer}`);
console.log(labels);
[ '#1 Ana', '#2 Ben', '#3 Ana', '#4 Cris' ]

Same length in, same length out. The original array isn't changed.

filter: keep only some items

const paid = orders.filter(order => order.status === "paid");
console.log(paid.map(order => order.id));
[ 1, 3 ]

The function returns true to keep an item and false to drop it. If nothing matches, you get an empty array, not undefined.

reduce: the whole list down to one value

const revenue = orders
  .filter(order => order.status === "paid")
  .reduce((sum, order) => sum + order.total, 0);
console.log(revenue);
1500

reduce takes a function and a starting value. sum starts at 0, and for each order the function returns the new sum. Read the chain top to bottom: keep the paid orders, add up their totals.

⚠ Warning: Always pass the starting value to reduce. Without it, reduce uses the first item as the start. For a sum of objects that means adding numbers to an object, and on an empty array it throws TypeError: Reduce of empty array with no initial value. An empty list of orders is normal. Your report shouldn't crash on a quiet day.

The relatives you'll use just as often

  • find: the first item that matches, or undefined. orders.find(o => o.id === 3).
  • some / every: true or false. "Is any order pending?" "Are all orders paid?"
  • includes: for simple values. ["paid", "pending"].includes(status).
  • toSorted: a sorted copy. orders.toSorted((a, b) => b.total - a.total). The older sort sorts the original array in place, which surprises people.

When a loop is clearer

reduce can do almost anything, which is the problem. Here's total per customer with reduce:

const byCustomer = orders.reduce((acc, o) => ({ ...acc, [o.customer]: (acc[o.customer] ?? 0) + o.total }), {});

It works. It also copies the whole object on every item and takes a minute to read. The loop:

const byCustomer = {};
for (const order of orders) {
  byCustomer[order.customer] = (byCustomer[order.customer] ?? 0) + order.total;
}
console.log(byCustomer);
{ Ana: 1500, Ben: 450, Cris: 900 }

My rule: use map and filter freely, reduce for sums and simple totals, and a loop when you're building an object, need to stop early, or need more than one line of logic per item. Nobody gets points for fitting it in one expression.

💡 Tip: When a chain gets long, give the middle steps names: const paidOrders = orders.filter(...). You can then console.log(paidOrders) while debugging instead of taking the chain apart.

Common mistakes

  • Forgetting return in a map callback with braces: orders.map(o => { o.total * 2 }) gives an array of undefined. Remove the braces or add return.
  • Using map just to loop, ignoring the result. Use for...of or forEach.
  • Changing the objects inside map (o.total = ...). map gives a new array, but the objects in it are the same objects.
  • Missing starting value in reduce.
  • Sorting the original array with sort when you meant to sort a copy.

What happens if you skip this

You'll keep writing loops with counters for everything, which is fine, until you have to read other people's code, which is full of these. Or you'll learn reduce first and use it for everything, and the next person who reads your report code will rewrite it to understand it.

How would you get the names of customers who have at least one paid order, without duplicates?

About

Use map, filter and reduce on a list of orders, plus find, some and toSorted, and know when a for...of loop reads better. After this, you can answer report questions in a few clear lines.

Duration
5 min
Last update
08/30/2026
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.