DEV Community

Snappy Tools
Snappy Tools

Posted on

JavaScript Array Methods: map, filter, reduce, and Everything Else You Need

JavaScript's array methods are one of those topics where the basics are well-known but the full picture saves significant time. Here's a practical reference, from the commonly used to the ones most developers forget exist.

The big three: map, filter, reduce

map — transform each element

map() creates a new array by applying a function to each element:

const prices = [10, 20, 30];
const withTax = prices.map(price => price * 1.2);
// [12, 24, 36]

const users = [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }];
const names = users.map(user => user.name);
// ['Alice', 'Bob']
Enter fullscreen mode Exit fullscreen mode

map() always returns an array of the same length. If you want to transform and potentially skip elements, use filter() + map() chained, or use reduce().

filter — select elements

filter() creates a new array containing only elements where the function returns true:

const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4, 6]

const activeUsers = users.filter(user => user.active);
Enter fullscreen mode Exit fullscreen mode

reduce — accumulate into a single value

reduce() is the most general but also most misunderstood. It takes an accumulator and current element, and returns the new accumulator value:

// Sum
const sum = [1, 2, 3, 4, 5].reduce((acc, curr) => acc + curr, 0);
// 15

// Count occurrences
const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'];
const counts = words.reduce((acc, word) => {
  acc[word] = (acc[word] || 0) + 1;
  return acc;
}, {});
// { apple: 3, banana: 2, cherry: 1 }

// Flatten one level
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, arr) => [...acc, ...arr], []);
// [1, 2, 3, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

The second argument (the 0 or {} above) is the initial accumulator. If you omit it, reduce() uses the first element — which works for numbers but can behave unexpectedly for objects.

Searching: find, findIndex, findLast

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];

// First element matching condition
users.find(u => u.id === 2)       // { id: 2, name: 'Bob' }

// Index of first match
users.findIndex(u => u.id === 2)  // 1

// Last element matching condition (ES2023)
users.findLast(u => u.id < 3)     // { id: 2, name: 'Bob' }

// Returns -1 or undefined if not found:
users.find(u => u.id === 99)      // undefined
users.findIndex(u => u.id === 99) // -1
Enter fullscreen mode Exit fullscreen mode

Checking: some, every, includes

const scores = [85, 90, 78, 95, 62];

// Does any element match?
scores.some(s => s >= 90)   // true

// Does every element match?
scores.every(s => s >= 60)  // true
scores.every(s => s >= 80)  // false

// Does the array contain this value?
scores.includes(90)  // true
[1, 2, NaN].includes(NaN)  // true — unlike indexOf
Enter fullscreen mode Exit fullscreen mode

some() returns true as soon as it finds a match. every() returns false as soon as it finds a non-match. Both short-circuit.

Sorting: sort

const fruits = ['banana', 'apple', 'cherry'];
fruits.sort()  // ['apple', 'banana', 'cherry'] — lexicographic sort in place

// Numeric sort (IMPORTANT — the default sort is string-based!)
[10, 9, 2, 21].sort()              // [10, 2, 21, 9] — WRONG for numbers
[10, 9, 2, 21].sort((a, b) => a - b)  // [2, 9, 10, 21] — correct ascending
[10, 9, 2, 21].sort((a, b) => b - a)  // [21, 10, 9, 2] — correct descending

// Sort objects by property
users.sort((a, b) => a.name.localeCompare(b.name));
Enter fullscreen mode Exit fullscreen mode

sort() modifies the original array in place. If you need a sorted copy, spread first: [...array].sort(...).

Flattening: flat, flatMap

// flat() — flatten nested arrays
[[1, 2], [3, 4]].flat()         // [1, 2, 3, 4]
[[1, [2, 3]], [4]].flat()       // [1, [2, 3], 4] — only one level deep
[[1, [2, 3]], [4]].flat(2)      // [1, 2, 3, 4] — two levels deep
[[1, [2, [3]]]].flat(Infinity)  // [1, 2, 3] — all levels

// flatMap() — map then flatten one level
const sentences = ['hello world', 'foo bar'];
sentences.flatMap(s => s.split(' '))  // ['hello', 'world', 'foo', 'bar']
// Equivalent to sentences.map(s => s.split(' ')).flat()
Enter fullscreen mode Exit fullscreen mode

Slice and splice

const arr = [1, 2, 3, 4, 5];

// slice — returns portion without modifying original
arr.slice(1, 3)    // [2, 3] — from index 1 (inclusive) to 3 (exclusive)
arr.slice(-2)      // [4, 5] — last 2 elements
arr.slice()        // [1, 2, 3, 4, 5] — shallow copy

// splice — modifies original, removes and/or inserts
arr.splice(1, 2)   // removes 2 elements starting at index 1, returns [2, 3]
// arr is now [1, 4, 5]

arr.splice(1, 0, 99)  // insert 99 at index 1, remove 0 elements
// arr is now [1, 99, 4, 5]
Enter fullscreen mode Exit fullscreen mode

A helpful mnemonic: slicE = no Effect on original, splicE = Effect on original.

Conversion: Array.from, Array.of, join

// Array.from — create array from iterable or array-like
Array.from('hello')              // ['h', 'e', 'l', 'l', 'o']
Array.from({length: 5}, (_, i) => i)  // [0, 1, 2, 3, 4]
Array.from(new Set([1, 2, 2, 3]))    // [1, 2, 3] — Set to array

// join — array to string
[1, 2, 3].join(', ')   // "1, 2, 3"
[1, 2, 3].join('')     // "123"
[1, 2, 3].join('\n')   // "1\n2\n3"

// toString is shorthand for join(',')
[1, 2, 3].toString()   // "1,2,3"
Enter fullscreen mode Exit fullscreen mode

at() — negative indexing

const arr = [10, 20, 30, 40, 50];
arr.at(0)   // 10
arr.at(-1)  // 50 — last element
arr.at(-2)  // 40 — second to last
Enter fullscreen mode Exit fullscreen mode

Cleaner than arr[arr.length - 1] for accessing from the end.

Structuring complex data transformations

For complex pipelines, chain methods clearly:

const result = users
  .filter(user => user.active)
  .map(user => ({
    id: user.id,
    displayName: `${user.firstName} ${user.lastName}`,
    email: user.email.toLowerCase()
  }))
  .sort((a, b) => a.displayName.localeCompare(b.displayName));
Enter fullscreen mode Exit fullscreen mode

This is easier to read and debug than a single complex reduce(). Reserve reduce() for accumulation (building an object, computing a sum) rather than using it as a general-purpose replacement for the other methods.


Array methods are one of those areas where knowing the full toolbox makes your code noticeably cleaner. find() instead of filter()[0], some() instead of a manual loop with a boolean flag, flatMap() instead of map().flat() — small choices that add up across a codebase.

Top comments (0)