DEV Community

Weather Clock Dash
Weather Clock Dash

Posted on

JavaScript Array Methods: map, filter, reduce, flatMap, and the ES2023 Immutable Ones

JavaScript array methods are one of the best investments in your day-to-day productivity. Once you internalize map, filter, reduce, and their siblings, most data transformations become a few readable lines instead of nested for loops.

The Core Three

map — Transform Each Element

map returns a new array with each element transformed:

const prices = [10, 25, 8, 42];
const withTax = prices.map(price => price * 1.1);
// [11, 27.5, 8.8, 46.2]

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

// Extract and rename
const simplified = users.map(({ name, age }) => ({ label: name, value: age }));
Enter fullscreen mode Exit fullscreen mode

filter — Keep Elements Matching a Condition

filter returns a new array with only the elements where the callback returns true:

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

const users = [
  { name: 'Alice', active: true },
  { name: 'Bob', active: false },
  { name: 'Carol', active: true }
];
const active = users.filter(u => u.active);
// [{ name: 'Alice' ... }, { name: 'Carol' ... }]
Enter fullscreen mode Exit fullscreen mode

reduce — Accumulate to a Single Value

reduce is the most versatile — it can implement any transformation, but it's most useful when you need to collapse an array into a single value:

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

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

// Group by property
const events = [
  { type: 'click', x: 10 },
  { type: 'scroll', y: 50 },
  { type: 'click', x: 30 }
];
const grouped = events.reduce((acc, event) => {
  (acc[event.type] = acc[event.type] || []).push(event);
  return acc;
}, {});
// { click: [...], scroll: [...] }
Enter fullscreen mode Exit fullscreen mode

Finding Elements

find and findIndex

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

const bob = users.find(u => u.id === 2);
// { id: 2, name: 'Bob' }

const bobIndex = users.findIndex(u => u.id === 2);
// 1

// Returns undefined (not -1) if not found
const nobody = users.find(u => u.id === 99);
// undefined
Enter fullscreen mode Exit fullscreen mode

some and every

const scores = [85, 92, 78, 95, 88];

const allPassing = scores.every(s => s >= 70);  // true
const anyPerfect = scores.some(s => s === 100);  // false
const anyFailing = scores.some(s => s < 70);     // false
Enter fullscreen mode Exit fullscreen mode

Flattening and Combining

flat and flatMap

const nested = [1, [2, 3], [4, [5, 6]]];
nested.flat();    // [1, 2, 3, 4, [5, 6]]
nested.flat(2);   // [1, 2, 3, 4, 5, 6]  — depth 2
nested.flat(Infinity);  // flatten any depth

// flatMap = map + flat(1)
const sentences = ['hello world', 'foo bar'];
const words = sentences.flatMap(s => s.split(' '));
// ['hello', 'world', 'foo', 'bar']

// Useful for expanding items conditionally
const items = [{ type: 'product', qty: 2 }, { type: 'gift' }];
const lines = items.flatMap(item =>
  item.qty > 1
    ? Array.from({ length: item.qty }, () => item)
    : [item]
);
Enter fullscreen mode Exit fullscreen mode

Sorting

sort mutates the array. Use a copy for immutability:

const numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// Wrong: sort() without comparator sorts lexicographically
numbers.sort();  // [1, 1, 2, 3, 4, 5, 6, 9] — works here by accident

// Right: always use a comparator for numbers
numbers.sort((a, b) => a - b);  // ascending
numbers.sort((a, b) => b - a);  // descending

// Strings
const words = ['banana', 'apple', 'cherry'];
words.sort();  // alphabetical: ['apple', 'banana', 'cherry']
words.sort((a, b) => a.localeCompare(b));  // locale-aware

// Objects
const users = [{ name: 'Charlie' }, { name: 'Alice' }, { name: 'Bob' }];
users.sort((a, b) => a.name.localeCompare(b.name));

// Immutable sort (ES2023)
const sorted = numbers.toSorted((a, b) => a - b);  // returns new array
Enter fullscreen mode Exit fullscreen mode

Checking and Searching

const arr = [1, 2, 3, NaN];

arr.includes(2);          // true
arr.includes(5);          // false
arr.includes(NaN);        // true  ← unlike indexOf

arr.indexOf(2);           // 1
arr.indexOf(5);           // -1
arr.indexOf(NaN);         // -1  ← NaN !== NaN

arr.lastIndexOf(2);       // 1 (searches from end)
Enter fullscreen mode Exit fullscreen mode

Array Construction

// Create array of length n
Array.from({ length: 5 }, (_, i) => i);  // [0, 1, 2, 3, 4]
Array.from({ length: 5 }, () => 0);      // [0, 0, 0, 0, 0]

// From iterable
Array.from('hello');           // ['h', 'e', 'l', 'l', 'o']
Array.from(new Set([1, 2, 2])); // [1, 2]  — deduplicate
Array.from(nodeList);          // NodeList to array

// Array.of
Array.of(1, 2, 3);  // [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Mutation Methods (use carefully)

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

arr.push(6);       // add to end, returns new length
arr.pop();         // remove from end, returns removed element
arr.unshift(0);    // add to start, returns new length
arr.shift();       // remove from start, returns removed element
arr.splice(1, 2);  // remove 2 elements at index 1, returns removed
arr.reverse();     // reverses in place

// Immutable alternatives (ES2023)
arr.toReversed();  // reversed copy
arr.toSpliced(1, 2);  // spliced copy
arr.with(2, 99);   // copy with arr[2] = 99
Enter fullscreen mode Exit fullscreen mode

Chaining

Methods chain naturally since most return arrays:

const data = [
  { name: 'Alice', score: 92, active: true },
  { name: 'Bob', score: 65, active: false },
  { name: 'Carol', score: 88, active: true },
  { name: 'Dave', score: 45, active: true }
];

const result = data
  .filter(u => u.active)        // only active users
  .filter(u => u.score >= 70)   // only passing scores
  .sort((a, b) => b.score - a.score)  // sort by score descending
  .map(u => `${u.name}: ${u.score}`)  // format
  .join(', ');
// "Alice: 92, Carol: 88"
Enter fullscreen mode Exit fullscreen mode

Performance Note

For very large arrays (millions of items), for...of loops are faster than chained array methods because they avoid creating intermediate arrays. For typical application data (hundreds to thousands of items), the readability benefit of array methods outweighs any performance difference.

The immutable methods (map, filter, reduce) are also better for React state management — they return new references, which is what React's reconciler checks to detect changes.

Top comments (0)