1. map, filter & reduce
These three cover the vast majority of everyday array work. Each one takes a callback and returns something different-shaped, which is exactly how to tell them apart:
const prices = [10, 20, 30];
const withTax = prices.map((price) => price * 1.08);
console.log(withTax); // [10.8, 21.6, 32.4] -- one output per input
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((n) => n % 2 === 0);
console.log(evens); // [2, 4, 6] -- only the elements that passed the test
const cart = [{ price: 10 }, { price: 20 }, { price: 30 }];
const total = cart.reduce((sum, item) => sum + item.price, 0);
console.log(total); // 60 -- the whole array collapsed into a single number
map always returns an array of the same length as the
original — one transformed value per input. filter returns an array
that's the same length or shorter, keeping only elements where the callback returned
true. reduce is the most flexible: it carries an accumulator through
every element and can produce a number, a string, an object, or even a brand-new
array — whatever the callback and starting value (0 above) build
toward.
prices, numbers and cart above are all completely unchanged after these calls. map, filter and reduce always return something new, which is exactly why they pair so well with the immutability habits Week 6 builds on.
2. find, some, every & includes
A different family of methods, for when the question isn't "transform this list" but "tell me something about it":
const users = [{ id: 1, name: "Ana" }, { id: 2, name: "Ben" }];
const user = users.find((u) => u.id === 2);
console.log(user); // { id: 2, name: "Ben" }
const scores = [72, 88, 95, 61];
const hasFailingScore = scores.some((s) => s < 60); // false -- at least one below 60?
const allPassing = scores.every((s) => s >= 60); // true -- every one at least 60?
const fruits = ["apple", "banana", "cherry"];
console.log(fruits.includes("banana")); // true -- just true/false, no callback needed
find answers "which one" and stops scanning the moment it finds a
match. some and every both answer yes/no questions and
also short-circuit — some stops at the first success,
every stops at the first failure. includes is the plainest
of the group: no callback, just "is this exact value anywhere in here?"
3. forEach vs. map
These two look almost identical and are easy to reach for interchangeably — but they exist for genuinely different purposes:
const items = ["pen", "notebook", "eraser"];
const result = items.forEach((item) => console.log(item));
console.log(result); // undefined -- forEach never returns anything useful
forEach runs a callback for every element and always returns
undefined — it exists purely for side effects, like logging or pushing
into an outside array. map exists to produce a new array; using
it just to log something (and throwing away the array it builds) works, but confuses
readers about the code's intent. A simple rule: if you're not using the return value,
reach for forEach. If you need a transformed array back, reach for
map.
4. sort & the Comparator
Array.prototype.sort() has a well-known trap: it sorts elements as
strings by default, which breaks silently on numbers:
const numbers = [10, 1, 21, 2];
console.log(numbers.sort()); // [1, 10, 2, 21] -- WRONG, sorted as text ("10" < "2")
const ascending = [10, 1, 21, 2].sort((a, b) => a - b);
console.log(ascending); // [1, 2, 10, 21] -- correct numeric order
const descending = [10, 1, 21, 2].sort((a, b) => b - a);
console.log(descending); // [21, 10, 2, 1]
A comparator returns a negative number when a should come first, a
positive number when b should come first, and 0 if they're
equal — a - b does exactly that for ascending numeric order, and
flipping it to b - a reverses it. Also worth knowing:
sort() mutates the original array in place. Spread it into a copy first
([...numbers].sort(...)) if the original order needs to survive.
5. Chaining Array Methods
Because map and filter both return a new array, calls can
be chained directly onto each other — building a pipeline that reads top-to-bottom
as a sequence of steps:
const orders = [
{ item: "Pen", price: 10, qty: 3, inStock: true },
{ item: "Mug", price: 150, qty: 2, inStock: false },
{ item: "Bag", price: 500, qty: 1, inStock: true },
];
const totalInStockValue = orders
.filter((order) => order.inStock) // keep only what's in stock
.map((order) => order.price * order.qty) // turn each into a line total
.reduce((sum, lineTotal) => sum + lineTotal, 0); // fold into one number
console.log(totalInStockValue); // 530
Read right to left through the logic, but top to bottom through the code: filter down to what qualifies, map each survivor to the value that actually matters, then reduce those values into a final answer. This chained shape is one of the most common patterns you'll see in real JavaScript — worth being fully comfortable reading and writing before Week 6 builds on it further.
A three-step chain like the one above loops over the data three separate times, not once. For everyday list sizes this is completely fine and far more readable than one dense hand-rolled loop — but it's worth knowing this trade-off exists once you're working with very large arrays where a single pass matters.
6. Hands-on Exercise
Build a small order-analytics report
Combine map, filter, reduce, find and sort on one array of order objects.
Requirements:
- Create an array of at least 6 order objects, each with
item,price,qtyandcategory(use 2–3 different categories). - Write a chained pipeline that returns the total value of orders in a single chosen category (
filter→map→reduce). - Use
findto locate the single most expensive individual order (byprice), and log itsitemname. - Use
everyto check whether every order has aqtygreater than 0, andsometo check whether any order's total line value (price * qty) exceeds 1000. - Produce a version of the array sorted by
pricedescending, using a comparator, without mutating the original array.
For step 3, reduce can find a max just as well as find can locate a specific one — but find is the right tool when you're checking a condition (like order.price === highestPrice) rather than computing one from scratch.
7. Knowledge Check
Four quick questions. Expand each to check your answer.
Q1
You need the total price of every item in a cart, as a single number. Which method is the right final step: map, filter, or reduce?
You need the total price of every item in a cart, as a single number. Which method is the right final step: map, filter, or reduce?
reduce. map and filter both return arrays, not a single value — only reduce is built to fold a whole array down into one final result, carrying a running total (the accumulator) through every element.
Q2
What's the practical difference between array.find(...) and array.filter(...) when the same condition would match more than one element?
What's the practical difference between array.find(...) and array.filter(...) when the same condition would match more than one element?
find returns only the first matching element itself (not an array), and stops scanning the moment it finds it. filter keeps scanning the whole array and returns every matching element as a new array — even if only one element matches, filter still returns an array (with one item in it), not the element itself.
Q3
Why does [10, 1, 21, 2].sort() (with no comparator) produce [1, 10, 2, 21] instead of numeric order?
Why does [10, 1, 21, 2].sort() (with no comparator) produce [1, 10, 2, 21] instead of numeric order?
Without a comparator, sort() converts every element to a string and compares them alphabetically — and as strings, "10" comes before "2" because "1" is alphabetically earlier than "2". Passing a comparator like (a, b) => a - b overrides this default and forces a real numeric comparison instead.
Q4
You call array.map(item => console.log(item)) purely to print each item, and never use the array it returns. What should you use instead, and why?
You call array.map(item => console.log(item)) purely to print each item, and never use the array it returns. What should you use instead, and why?
forEach. It exists specifically for side effects like logging, where no new array is needed — using map here still works, but it builds and immediately discards a whole array of undefined values (since console.log returns undefined), which misleads anyone reading the code into thinking a transformed array matters.