Introduction
In JavaScript a function is a value: it can be stored in a variable and passed to another function. A function passed in this way is called a callback. Arrays have methods that call a callback for every item, so most loops over data can be one clear line. The benefit is more than saving typing, because filter tells the reader the purpose at once, while a loop has to be read to find out.
How it works
| Method | Calls the callback with | Gives back |
|---|---|---|
forEach(fn) | each item | nothing (undefined) |
map(fn) | each item | a new array of the callback's results |
filter(fn) | each item | a new array of the items where the callback gave true |
find(fn) | each item until one matches | that item, or undefined |
some(fn), every(fn) | each item | true if any / all match |
reduce(fn, start) | a running total and each item | the final total |
Step through the example below: every call of the arrow function gets its own frame on the call stack, with p set to the next item.
reduce. reduce keeps a running value. The callback gets the value so far (often called acc, the accumulator) and the next item, and returns the new value so far:
// reduce: a running total over the items.
const orders = [
{ item: "pen", qty: 3, price: 10 },
{ item: "book", qty: 1, price: 250 },
{ item: "bag", qty: 2, price: 400 },
];
const total = orders.reduce((acc, o) => acc + o.qty * o.price, 0);
console.log("Total:", total);
const names = orders.filter((o) => o.price > 50).map((o) => o.item);
console.log(names);
const sorted = [...orders].sort((a, b) => b.price - a.price);
console.log(sorted.map((o) => o.item).join(", "));Sorting. sort() changes the array. Without a callback it sorts as text, so [10, 9, 1].sort() gives [1, 10, 9]. For numbers, pass a compare function: nums.sort((a, b) => a - b). A negative result puts a first, a positive one puts b first. Sorting is stable, so items that compare equal keep their original order. To compare text in a friendly way, use a.localeCompare(b).
Syntax
const doubled = nums.map((n) => n * 2);
const big = nums.filter((n) => n > 10);
const total = nums.reduce((acc, n) => acc + n, 0);
const ordered = [...nums].sort((a, b) => a - b);
Example
// map, filter and find with arrow-function callbacks.
const prices = [120, 45, 300, 80];
const withVat = prices.map((p) => p * 1.15);
console.log(withVat);
const cheap = prices.filter((p) => p < 100);
console.log("Under 100:", cheap);
const big = prices.find((p) => p > 200);
console.log("First over 200:", big);
console.log(prices.some((p) => p > 250), prices.every((p) => p > 50));Line by line
pricesis the list to work on.mapruns the callback for each price and collects the results. The long decimal is the usual rounding error.filterkeeps only the prices for which the callback gives true.findstops at the first match, so it gives one item, not a list.someis true because 300 is over 250.everyis false because 45 is not over 50.
Expected result
[ 138, 51.74999999999999, 345, 92 ]
Under 100: [ 45, 80 ]
First over 200: 300
true false
In the real world
A shop page filters products by category, maps them to cards, and reduces the cart to a total. Interface libraries such as React use map to turn data into a list on screen, so you will write these methods constantly.
Common mistakes
- Forgetting
returnin a callback with braces.map((x) => { x * 2 })givesundefinedfor every item. Writemap((x) => x * 2). - Using
mapjust to loop. If you do not need the new array, useforEachorfor...of. - Sorting numbers without a compare function.
- Forgetting the starting value of
reduce. On an empty array it throws a TypeError. - Sorting a list you do not own.
sortchanges it in place, so copy first with[...list].
Best practices
- Chain small steps, each with one clear job.
- Keep callbacks short, and give a long one a name.
- Choose the most specific method:
findfor one item,somefor a yes or no.
Summary
Callbacks let array methods do the looping for you. map transforms, filter selects, find looks for one item and reduce combines everything into one value. sort changes the array, and needs a compare function for numbers.
Quick check
Key takeaways
- map, filter and reduce give new values and leave the original alone.
- sort changes the array and compares as text unless you give it a compare function.
- Chaining small steps often reads better than one large loop.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.