EXERCISE
1The real power shows up when you chain filter and map together. Filter first to narrow down, then map to transform. Clean, readable, no loops.
Because filter and map both return arrays, they chain. The usual order is to reduce the set first and then transform what is left, which is both clearer and less work.
const orders = [
{ item: "book", price: 12, shipped: true },
{ item: "pen", price: 2, shipped: false },
{ item: "lamp", price: 40, shipped: true },
];
const shippedPrices = orders
.filter((o) => o.shipped)
.map((o) => o.price);
console.log(shippedPrices); // [12, 40]
Read it as a sentence: keep the shipped orders, then take each price. Each line does one thing, and the name of the method says which.
Order matters for cost, and sometimes for correctness:
const a = orders.filter((o) => o.shipped).map((o) => o.price);
const b = orders.map((o) => o.price).filter((p) => p > 0);
The first filters three elements and then transforms two. The second transforms all three and then filters. With three orders this is irrelevant; with fifty thousand it is not, and filtering first is the habit worth having.
Correctness can depend on it too:
const withRatio = orders
.filter((o) => o.price > 0)
.map((o) => 100 / o.price);
Reversing those two lines would divide by zero before the guard had a chance to remove the offending element.
Chains can be longer, and stay readable as long as each step is one idea:
const names = orders
.filter((o) => o.shipped)
.filter((o) => o.price > 10)
.map((o) => o.item.toUpperCase());
console.log(names); // ["BOOK", "LAMP"]
Two separate filters rather than one condition joined by && is a deliberate choice. Each line can be read, commented or removed on its own, and when a bug appears you can delete one line to find out which condition is wrong.
The cost is an extra pass over the array. That is the right trade almost always, and knowing you made it is what matters.
One property makes chains safe to build up incrementally: each step receives a fresh array, so no step can disturb what an earlier one produced.
const shipped = orders.filter((o) => o.shipped);
const prices = shipped.map((o) => o.price);
console.log(orders.length); // 3
console.log(shipped.length); // 2
console.log(prices.length); // 2
Splitting a chain into named steps like this costs nothing at runtime and is often the fastest way to find which step is wrong.