Array Methods & Iteration
Transform and analyze data with functional array methods used daily in production JavaScript.
map, filter, and reduce
`map` transforms each element and returns a new array of the same length. `filter` selects elements matching a predicate. `reduce` folds the array into a single accumulated value — sums, grouping, and object building are common uses.
These methods do not mutate the original array, supporting immutable data patterns. Chain them for readable pipelines, but extract named steps when chains grow beyond three operations for testability.
- `map` — transform each item
- `filter` — select subset
- `reduce` — aggregate to single value
const total = orders .filter(o => o.status === 'paid') .map(o => o.amount) .reduce((sum, n) => sum + n, 0);
find, some, every, and includes
`find` returns the first matching element or `undefined`. `some` and `every` short-circuit boolean checks across elements. `includes` checks value presence with SameValueZero equality (handles `NaN`).
Use `find` instead of `filter()[0]` when you only need one match — `find` stops early. For existence checks, prefer `some` over `find` !== undefined for clearer intent.
- `find` short-circuits on first match
- `some`/`every` for boolean predicates
- `includes` for primitive presence
const admin = users.find(u => u.role === 'admin'); const hasErrors = fields.some(f => f.error);
flat, flatMap, and Spread
`flat(depth)` flattens nested arrays. `flatMap` maps then flattens one level, ideal for expanding items into multiple outputs without nested loops.
Spread syntax `[...arr1, ...arr2]` concatenates arrays immutably. For large arrays, consider whether mutation with `push` in a loop is necessary for performance, but default to immutable patterns unless profiling shows a bottleneck.
- `flatMap` = map + flat(1)
- Spread for immutable concat
- Specify depth for deeply nested flat
const sentences = paragraphs.flatMap(p => p.split('. '));sort, slice, and Immutable Updates
`sort` mutates in place — copy first with `[...arr].sort(compareFn)` when immutability matters. Always provide a compare function for numbers; default sort converts to strings.
`slice` extracts portions without mutation. Combine with spread for insert/remove/replace patterns in state updates without libraries like Immer.
- Copy before `sort` for immutability
- Always pass compare function for numbers
- `slice` and spread for non-mutating edits
const sorted = [...scores].sort((a, b) => b - a); const updated = [...items.slice(0, i), newItem, ...items.slice(i + 1)];
Choosing the Right Method
Prefer declarative array methods over manual `for` loops when readability wins. Use `for...of` when you need `break`, `continue`, or async/await inside the loop — array methods do not await async callbacks in `map` the way a `for...of` loop does.
For very large datasets, measure performance — a tight `for` loop can beat chained methods. In typical UI data sizes (hundreds to low thousands of items), clarity matters more than micro-optimizations.
- Use `for...of` with async/await in loops
- Measure before optimizing large arrays
- Extract complex chains into named functions