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 })); 

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' ... }] 

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: [...] } 

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 

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 

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] ); 

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 

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) 

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] 

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 

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" 

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.