Overview
Modern JavaScript provides a rich set of array methods that replace manual loops. Learning them well makes code shorter, more declarative, and less error-prone. This tutorial covers the methods you will use every day, with examples and comparisons.
Why Use Array Methods
// Imperative loop
const doubled = [];
for (let i = 0; i < numbers.length; i++) {
doubled.push(numbers[i] * 2);
}
// Declarative method
const doubled = numbers.map(n => n * 2);
The declarative version states what should happen, not how to iterate. It is shorter, avoids off-by-one errors, and composes cleanly with other methods.
map
Transforms each element and returns a new array of the same length.
const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.2);
// [12, 24, 36]
const users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
const names = users.map(u => u.name);
// ["Alice", "Bob"]
filter
Returns a new array containing only elements that pass a test.
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4, 6]
const activeUsers = users.filter(u => u.active);
reduce
Combines all elements into a single value. The most flexible and often the most misunderstood method.
const numbers = [1, 2, 3, 4];
// Sum
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 10
// Group by property
const orders = [
{ customer: "Alice", amount: 100 },
{ customer: "Bob", amount: 50 },
{ customer: "Alice", amount: 200 },
];
const totals = orders.reduce((acc, order) => {
acc[order.customer] = (acc[order.customer] || 0) + order.amount;
return acc;
}, {});
// { Alice: 300, Bob: 50 }
Always provide the initial value. Omitting it causes reduce to use the first element as the initial accumulator, which fails on empty arrays and can produce surprising types.
find and findIndex
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
];
users.find(u => u.id === 2); // { id: 2, name: "Bob" }
users.findIndex(u => u.id === 2); // 1
users.find(u => u.id === 99); // undefined
some and every
const numbers = [2, 4, 6, 8];
numbers.some(n => n > 7); // true
numbers.some(n => n > 10); // false
numbers.every(n => n % 2 === 0); // true
| Method | Returns | Short-circuits |
|---|---|---|
some | Boolean | Yes, on first true |
every | Boolean | Yes, on first false |
flat and flatMap
const nested = [[1, 2], [3, 4], [5]];
nested.flat(); // [1, 2, 3, 4, 5]
nested.flat(2); // flatten two levels
const sentences = ["hello world", "foo bar"];
sentences.flatMap(s => s.split(" "));
// ["hello", "world", "foo", "bar"]
sort
sort mutates the array and converts elements to strings by default. This causes the classic [10, 9, 80].sort() bug.
const nums = [10, 9, 80];
nums.sort(); // [10, 80, 9] — string comparison
nums.sort((a, b) => a - b); // [9, 10, 80] — numeric
// Non-mutating alternative
const sorted = [...nums].sort((a, b) => a - b);
Array Method Comparison
| Method | Returns | Mutates original |
|---|---|---|
map | New array, same length | No |
filter | New array, shorter or equal | No |
reduce | Any value | No |
find | Element or undefined | No |
some / every | Boolean | No |
sort | Same array, sorted | Yes |
reverse | Same array, reversed | Yes |
splice | Removed elements | Yes |
slice | New array copy | No |
push / pop | New length / removed element | Yes |
Chaining Methods
const orders = [
{ customer: "Alice", amount: 100, status: "completed" },
{ customer: "Bob", amount: 50, status: "pending" },
{ customer: "Alice", amount: 200, status: "completed" },
];
const aliceTotal = orders
.filter(o => o.customer === "Alice")
.filter(o => o.status === "completed")
.map(o => o.amount)
.reduce((sum, amount) => sum + amount, 0);
// 300
Chaining is readable when each step is a clear transformation. If a chain grows beyond four or five methods, consider extracting helper functions or intermediate variables for clarity.
Performance Notes
- Each chained method creates a new array. For very large datasets, combine passes or use a
forloop. findandsomeshort-circuit;mapandfilteralways visit every element.- Do not use
mapwhen you only need side effects; useforEachinstead. - Do not use
filter(...).length > 0whensomewill do.
