Start.dev
Back to blog

JavaScript array methods: map, filter, reduce and more

Learn the JavaScript array methods you will use daily: map, filter, find, some, every, reduce and sort, with runnable examples on one shopping cart.

Ariel Weinberger
Ariel Weinberger ยท 5 min read

JavaScript array methods let you describe what you want from a list instead of writing the loop that gets it. map transforms every item, filter keeps the ones that match, reduce collapses the array into a single value, and a few more (find, some, every, sort) answer the questions you ask most often. Once you can pick the right one, a lot of loop code turns into a single readable line.

This guide walks through each method on one shopping cart, so you can see how they differ and how they fit together. Every example runs as written.

const cart = [
  { name: "Notebook", price: 12, qty: 2 },
  { name: "Pen", price: 3, qty: 10 },
  { name: "Backpack", price: 45, qty: 1 },
  { name: "Stapler", price: 9, qty: 0 },
]

Start from the loop you already know

Say you want the name of every item. With a for...of loop, you build the result by hand:

const names = []
 
for (const item of cart) {
  names.push(item.name)
}
 
console.log(names) // [ 'Notebook', 'Pen', 'Backpack', 'Stapler' ]

That works, and the For Of (opens in a new tab) lesson in JavaScript Basics covers it properly. But three of those lines are bookkeeping: make an empty array, push into it, keep track of it. Array methods remove the bookkeeping. They take a small function, called a callback, that describes what to do with one item, and they run it for every item.

forEach is the simplest of them. It calls your function once per item and returns nothing, so it is the right choice when you only want a side effect like logging. The Foreach (opens in a new tab) lesson in Intermediate JavaScript shows why it is the shape behind the rest.

map: transform every item

map returns a new array with one result for each item in the original. The output always has the same length as the input.

const names = cart.map((item) => item.name)
console.log(names) // [ 'Notebook', 'Pen', 'Backpack', 'Stapler' ]
 
const lineTotals = cart.map((item) => item.price * item.qty)
console.log(lineTotals) // [ 24, 30, 45, 0 ]

The original cart is untouched. Reach for map whenever you think "I want the same list, but each item turned into something else." The Map (opens in a new tab) lesson has you practice it.

filter: keep what matches

filter returns a new array containing only the items for which your callback returns a truthy value. The output can be shorter than the input, or empty.

const inStock = cart.filter((item) => item.qty > 0)
console.log(inStock.map((item) => item.name))
// [ 'Notebook', 'Pen', 'Backpack' ]

Your callback can read variables from the code around it, like a minQty you defined earlier. That works because callbacks are closures, and it is the reason array methods feel so flexible. The Filter (opens in a new tab) lesson builds on it.

find, some, and every: ask a question

Sometimes you do not want a new array. You want one item, or a yes or no.

const pen = cart.find((item) => item.name === "Pen")
console.log(pen) // { name: 'Pen', price: 3, qty: 10 }
 
console.log(cart.find((item) => item.name === "Mug")) // undefined
 
console.log(cart.some((item) => item.qty === 0))  // true
console.log(cart.every((item) => item.price > 0)) // true

find returns the first match, or undefined if nothing matches, so check before you use the result. some asks whether at least one item passes, and every asks whether all of them do. All three stop as soon as the answer is known. For looking up a plain value like a number or string, the Searching (opens in a new tab) lesson covers simpler tools, and Find And Some (opens in a new tab) covers these.

reduce: collapse to one value

reduce is the one people find intimidating, mostly because of its extra argument. It walks the array while carrying a running value, called the accumulator, and returns whatever the accumulator holds at the end.

const total = cart.reduce((sum, item) => sum + item.price * item.qty, 0)
console.log(total) // 99

Read it step by step. The 0 at the end is the starting value for sum. For each item, the callback returns the new sum, and that becomes the sum for the next item: 0, then 24, then 54, then 99, then 99 again for the Stapler. The result of the last call is the result of reduce.

Always pass that starting value. Without it, reduce uses the first item as the start, and on an empty array it throws a TypeError instead of giving you a sensible result. Totals, counts, and averages are the common jobs, and the Reduce Sum (opens in a new tab) lesson goes through them.

The accumulator does not have to be a number. It can be an object, which is handy for lookups:

const priceByName = cart.reduce((lookup, item) => {
  lookup[item.name] = item.price
  return lookup
}, {})
 
console.log(priceByName)
// { Notebook: 12, Pen: 3, Backpack: 45, Stapler: 9 }

Chain them together

Each of these methods returns an array, so you can call the next one straight on the result. This is the payoff:

const receiptTotal = cart
  .filter((item) => item.qty > 0)
  .map((item) => item.price * item.qty)
  .reduce((sum, amount) => sum + amount, 0)
 
console.log(receiptTotal) // 99

Read it top to bottom as a sentence: keep the items in stock, turn each into a line total, add them up. Every step is an expression that produces a value, which is exactly why they snap together. Put each method on its own line and the chain reads like a recipe. The Chaining (opens in a new tab) lesson is the place to practice it.

sort: order an array, with two catches

sort takes a comparison function that returns a negative number, zero, or a positive number. For prices, subtract one from the other:

const cheapestFirst = [...cart].sort((a, b) => a.price - b.price)
console.log(cheapestFirst.map((item) => item.name))
// [ 'Pen', 'Stapler', 'Notebook', 'Backpack' ]

The first catch is in that [...cart]. Unlike map and filter, sort changes the array it is called on. Copying first keeps cart in its original order. This is the same reference behavior covered in value vs reference in JavaScript. Newer runtimes also have toSorted, which does the copy for you.

The second catch is that sort with no comparison function compares items as strings:

console.log([10, 9, 1].sort()) // [ 1, 10, 9 ]

Always pass a comparison function for numbers. The Sort (opens in a new tab) lesson goes deeper.

Which method do you need?

You want to...UseReturns
Run code for each item, nothing backforEachundefined
Turn every item into something elsemapNew array, same length
Keep only some itemsfilterNew array, same or shorter
Get the first matchfindOne item or undefined
Ask if any or all items passsome / everytrue or false
Combine everything into one valuereduceWhatever the accumulator is

Three mistakes to watch for

Forgetting return when you use braces. An arrow function with { } needs an explicit return, or every result is undefined:

const broken = cart.map((item) => { item.price * item.qty })
console.log(broken) // [ undefined, undefined, undefined, undefined ]

Drop the braces for a one-liner, or add return.

Using map when you only want a side effect. If you are not using the array map returns, you wanted forEach.

Passing an async function to map. You get an array of promises, not values. Wrap it in Promise.all and await the whole thing:

const results = await Promise.all(ids.map(async (id) => fetchUser(id)))

The Promise All (opens in a new tab) lesson explains why, and async/await explained covers the background.

Where to go from here

The fastest way to make these stick is to rewrite loops you already have. Next time you reach for for and an empty array, ask whether it is really a map, a filter, or a reduce. If the methods feel shaky, start with arrays and loops in JavaScript Basics (opens in a new tab). If you are ready to chain them on real data, Intermediate JavaScript (opens in a new tab) builds a project around exactly that.

Level up your coding skills

Jump into interactive courses and start building real-world projects.

Start learning

Related posts

Learn JavaScript closures with tested examples: counters, the var vs let loop question, private state, debounce, and the stale closure bug in React hooks.
Brad Traversy
Brad Traversy ยท 8 min read
You copied an array, changed the copy, and the original changed too. Here is what a JavaScript variable actually holds and how to copy safely.
Ariel Weinberger
Ariel Weinberger ยท 6 min read
You can read JavaScript but keep forgetting how to write it. The difference between an expression and a statement explains most of the syntax.
Ariel Weinberger
Ariel Weinberger ยท 11 min read