JavaScript · Arrays & Iteration

JavaScript Array Methods Explained — map, filter, reduce and the Iteration Toolkit

7 min read Updated 2026-06-18

Practice Array Methods interview questions

Thinking in array methods

Arrays are the workhorse data structure of JavaScript, and the language gives you a rich set of higher-order methods for transforming and querying them. Instead of writing manual for loops, you describe what you want — "map each item," "keep the matches," "boil it down to one value" — and the method handles the iteration. This declarative style is more readable, less bug-prone, and composes into expressive pipelines. Mastering these methods is one of the highest-leverage skills in everyday JavaScript.

This guide walks through the core iteration methods, what each returns, and the patterns interviewers and codebases lean on.

map — transform every element

map creates a new array by applying a function to each element. The result is always the same length as the input. Use it whenever you want to transform a collection.

const nums = [1, 2, 3]
const doubled = nums.map(n => n * 2)        // [2, 4, 6]
const names = users.map(u => u.name)        // extract a field

The key property: map is non-mutating and length-preserving. A common mistake is using map for side effects (like logging) and ignoring the return value — if you don't need the new array, use forEach instead.

filter — keep what matches

filter returns a new array containing only the elements for which the predicate returns truthy. The result is the same length or shorter.

const evens = [1, 2, 3, 4].filter(n => n % 2 === 0)   // [2, 4]
const active = users.filter(u => u.isActive)           // subset

filter pairs naturally with map: filter first to narrow, then map to transform. Chaining them reads top-to-bottom like a description of the data flow.

const activeNames = users
  .filter(u => u.isActive)
  .map(u => u.name)        // clear pipeline

reduce — boil down to one value

reduce is the most general method: it walks the array carrying an accumulator, combining each element into a single result. That result can be a number, string, object, or even another array.

const sum = [1, 2, 3, 4].reduce((acc, n) => acc + n, 0)   // 10

The second argument (0 here) is the initial value — always provide it. Without it, reduce uses the first element as the seed, which breaks on empty arrays (throws) and can cause subtle off-by-one bugs.

reduce shines for building objects, such as grouping or indexing:

const byId = users.reduce((acc, u) => {
  acc[u.id] = u
  return acc          // must return the accumulator
}, {})

Forgetting to return acc is the number-one reduce bug — the accumulator becomes undefined on the next iteration.

forEach — iterate for side effects

forEach runs a function for each element but returns undefined — it's for side effects, not transformation.

items.forEach(item => console.log(item))   // logging
items.forEach(item => save(item))          // side effect

Unlike a for loop, you cannot break out of forEach early. If you need early exit, use a for...of loop or some/find. Don't reach for forEach when map/filter/reduce expresses the intent better.

some and every — boolean queries

some asks "does at least one element match?" and every asks "do all elements match?" Both return a boolean and short-circuit as soon as the answer is determined.

const hasNegative = nums.some(n => n < 0)    // stops at first match
const allPositive = nums.every(n => n > 0)   // stops at first failure

A gotcha worth remembering: every on an empty array returns true (vacuous truth) and some returns false. Guard for emptiness if "all valid" shouldn't pass when there's no data.

find and findIndex — locate one element

find returns the first element matching a predicate (or undefined); findIndex returns its index (or -1). Both short-circuit on the first match.

const user = users.find(u => u.id === 7)        // the object, or undefined
const idx = users.findIndex(u => u.id === 7)    // its index, or -1

Use find instead of filter(...)[0] — it stops at the first match rather than scanning the whole array. Always treat the result as possibly undefined (optional chaining helps: user?.name). The reverse-direction variants findLast and findLastIndex search from the end.

flat and flatMap — flattening

flat flattens nested arrays one level by default (pass a depth, or Infinity, for deeper). flatMap maps and then flattens one level in a single pass — perfect for "expand each element into zero or more."

[[1, 2], [3, 4]].flat()              // [1, 2, 3, 4]
[1, 2, 3].flatMap(n => [n, n * 10])  // [1, 10, 2, 20, 3, 30]
words.flatMap(w => w.split(''))      // explode into characters

flatMap is also handy for filtering-while-mapping: return [] to drop an element and [value] to keep it.

Array.from and Array.of — creation

Array.from builds an array from anything iterable or array-like, with an optional mapping function. Array.of creates an array from its arguments (avoiding the confusing single-number Array(3) behavior).

Array.from('abc')                       // ['a', 'b', 'c']
Array.from({ length: 3 }, (_, i) => i)  // [0, 1, 2] array-like + map
Array.from(document.querySelectorAll('li'))  // NodeList -> real array
Array.of(7)                             // [7] (vs Array(7) = empty length-7)

Array.from with a mapping function is the cleanest way to generate sequences.

entries, keys, and values — iterators

These return iterators for use with for...of and destructuring. entries is especially useful when you need both index and value.

for (const [i, value] of arr.entries()) {
  console.log(i, value)   // index AND value
}

This is cleaner than tracking an index manually and pairs perfectly with array destructuring.

Chaining and performance

The real power emerges when you chain methods into a readable pipeline:

const result = orders
  .filter(o => o.status === 'paid')
  .map(o => o.total)
  .reduce((sum, t) => sum + t, 0)   // total revenue from paid orders

Each step creates an intermediate array, so for very large datasets or hot paths, a single reduce or a plain loop can be more efficient (no intermediates). But for the vast majority of code, clarity wins — chain freely and optimize only when profiling shows a real problem.

Choosing the right method

A quick mental map: transform -> map; select a subset -> filter; combine to one value -> reduce; just do something per item -> forEach; existence/universality checks -> some/ every; locate one -> find/findIndex; expand/flatten -> flatMap/flat. Picking the method that names your intent makes code self-documenting.

Key takeaways

  • map transforms (same length, new array); filter selects a subset; reduce folds to a single value — the three pillars.
  • Always pass reduce an initial value and remember to return the accumulator.
  • forEach is for side effects and can't break; use for...of or some/find for early exit.
  • some/every short-circuit and return booleans; every is true on an empty array.
  • find/findIndex locate one element; treat find's result as possibly undefined.
  • flatMap, flat, Array.from, and entries round out the toolkit for flattening, creation, and index-aware iteration.

These methods turn loops into declarative pipelines — learn them well and most array work becomes a one-line expression of intent.

Practice tests are coming soon

Get notified when interactive mock interviews and quizzes launch.