DEV Community

楊東霖
楊東霖

Posted on • Originally published at devtoolkit.cc

JavaScript Array Methods: Complete Guide (map, filter, reduce, and More)

JavaScript arrays are the backbone of nearly every application you'll write. But knowing which array method to reach for — and how to chain them efficiently — is what separates clean, expressive code from verbose, bug-prone loops. This guide covers every modern JavaScript array method with working examples you can run directly in your browser console.

The Core Iteration Methods

Array.prototype.map()

map() creates a new array by transforming each element through a callback function. The original array is never modified. It's the right choice any time you want to convert every item in a collection.

const prices = [10, 25, 50, 100];
const withTax = prices.map(price => price * 1.08);
console.log(withTax); // [10.8, 27, 54, 108]

// Transforming objects
const users = [
  { id: 1, name: 'Alice', role: 'admin' },
  { id: 2, name: 'Bob',   role: 'user'  },
];
const names = users.map(u => u.name);
console.log(names); // ['Alice', 'Bob']

// Map with index
const indexed = ['a', 'b', 'c'].map((item, i) => `${i}: ${item}`);
console.log(indexed); // ['0: a', '1: b', '2: c']
Enter fullscreen mode Exit fullscreen mode

The callback receives three arguments: (currentValue, index, array). You rarely need index and almost never need the third argument, but they're there when you do.

Array.prototype.filter()

filter() returns a new array containing only the elements for which the callback returns a truthy value. It's your go-to for narrowing down a collection.

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

const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]

const odds = numbers.filter(n => n % 2 !== 0);
console.log(odds); // [1, 3, 5, 7, 9]

// Filter objects by property
const products = [
  { name: 'Widget', inStock: true,  price: 9.99  },
  { name: 'Gadget', inStock: false, price: 19.99 },
  { name: 'Doohickey', inStock: true, price: 4.99 },
];
const available = products.filter(p => p.inStock);
console.log(available.map(p => p.name)); // ['Widget', 'Doohickey']

// Remove falsy values (null, undefined, 0, '', NaN)
const mixed = [0, 1, false, 2, '', 3, null, undefined, 4];
const truthy = mixed.filter(Boolean);
console.log(truthy); // [1, 2, 3, 4]
Enter fullscreen mode Exit fullscreen mode

Array.prototype.reduce()

reduce() is the most powerful and flexible array method. It "folds" an array down to a single value by executing a reducer function against an accumulator and each element. The initial value of the accumulator is the second argument to reduce().

// Sum all values
const totals = [10, 20, 30, 40];
const sum = totals.reduce((acc, val) => acc + val, 0);
console.log(sum); // 100

// Find the maximum
const scores = [45, 89, 23, 91, 67];
const max = scores.reduce((best, score) => score > best ? score : best, -Infinity);
console.log(max); // 91

// Build an object from an array
const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'];
const frequency = words.reduce((acc, word) => {
  acc[word] = (acc[word] || 0) + 1;
  return acc;
}, {});
console.log(frequency);
// { apple: 3, banana: 2, cherry: 1 }

// Flatten one level (see flat() for a cleaner option)
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
console.log(flat); // [1, 2, 3, 4, 5, 6]

// Group objects by a property
const people = [
  { name: 'Alice', dept: 'engineering' },
  { name: 'Bob',   dept: 'marketing'   },
  { name: 'Carol', dept: 'engineering' },
];
const byDept = people.reduce((groups, person) => {
  const dept = person.dept;
  groups[dept] = groups[dept] || [];
  groups[dept].push(person.name);
  return groups;
}, {});
console.log(byDept);
// { engineering: ['Alice', 'Carol'], marketing: ['Bob'] }
Enter fullscreen mode Exit fullscreen mode

Always provide an initial value to reduce(). Without it, the first element becomes the accumulator, which causes bugs when the array is empty (it throws a TypeError).

Search and Find Methods

find() and findIndex()

find() returns the first element that satisfies the predicate (or undefined). findIndex() returns its index (or -1). Both short-circuit — they stop iterating as soon as a match is found.

const inventory = [
  { id: 1, sku: 'A100', qty: 50  },
  { id: 2, sku: 'B200', qty: 0   },
  { id: 3, sku: 'C300', qty: 120 },
];

const item = inventory.find(i => i.sku === 'B200');
console.log(item); // { id: 2, sku: 'B200', qty: 0 }

const idx = inventory.findIndex(i => i.qty === 0);
console.log(idx); // 1

// findLast and findLastIndex (ES2023)
const lastOut = inventory.findLast(i => i.qty === 0);
Enter fullscreen mode Exit fullscreen mode

includes(), indexOf(), lastIndexOf()

const fruits = ['apple', 'banana', 'cherry', 'banana'];

// Simple existence check — prefer includes() for primitives
console.log(fruits.includes('banana'));    // true
console.log(fruits.includes('grape'));     // false

// First occurrence index
console.log(fruits.indexOf('banana'));     // 1
console.log(fruits.indexOf('grape'));      // -1

// Last occurrence index
console.log(fruits.lastIndexOf('banana')); // 3

// NaN check — includes() handles NaN correctly, indexOf() doesn't
const vals = [1, NaN, 3];
console.log(vals.includes(NaN));  // true
console.log(vals.indexOf(NaN));   // -1  ← bug-prone!
Enter fullscreen mode Exit fullscreen mode

some() and every()

These return boolean values and both short-circuit early:

const ages = [22, 17, 30, 15, 28];

// Does at least one element satisfy the condition?
const hasMinors = ages.some(age => age < 18);
console.log(hasMinors); // true

// Do ALL elements satisfy the condition?
const allAdults = ages.every(age => age >= 18);
console.log(allAdults); // false

// Practical: validate form fields
const fields = [
  { name: 'email',    value: 'user@example.com', valid: true  },
  { name: 'username', value: 'alice',             valid: true  },
  { name: 'password', value: '',                  valid: false },
];
const formValid = fields.every(f => f.valid);
console.log(formValid); // false
Enter fullscreen mode Exit fullscreen mode

Transformation Methods

flat() and flatMap()

Introduced in ES2019, flat() collapses nested arrays by a specified depth. flatMap() combines a map() and a one-level flat() in one pass — more efficient than chaining them.

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

// flatMap() — map then flatten one level
const sentences = ['Hello World', 'Foo Bar'];
const allWords = sentences.flatMap(s => s.split(' '));
console.log(allWords); // ['Hello', 'World', 'Foo', 'Bar']

// flatMap is useful for 1-to-many transformations
const orders = [
  { id: 1, items: ['pen', 'notebook'] },
  { id: 2, items: ['stapler']         },
];
const allItems = orders.flatMap(order => order.items);
console.log(allItems); // ['pen', 'notebook', 'stapler']
Enter fullscreen mode Exit fullscreen mode

sort()

sort() sorts in place (mutates the original array). Without a comparator it sorts lexicographically — which breaks numeric sorting.

// ⚠️ Default lexicographic sort — wrong for numbers
const nums = [10, 1, 21, 2];
console.log(nums.sort()); // [1, 10, 2, 21] — WRONG

// ✅ Correct numeric sort
console.log([10, 1, 21, 2].sort((a, b) => a - b)); // [1, 2, 10, 21]
console.log([10, 1, 21, 2].sort((a, b) => b - a)); // [21, 10, 2, 1]

// Sort strings
const names = ['Charlie', 'Alice', 'Bob'];
names.sort((a, b) => a.localeCompare(b));
console.log(names); // ['Alice', 'Bob', 'Charlie']

// Sort objects by property
const employees = [
  { name: 'Dave',  salary: 75000 },
  { name: 'Eve',   salary: 90000 },
  { name: 'Frank', salary: 60000 },
];
employees.sort((a, b) => b.salary - a.salary);
console.log(employees.map(e => e.name)); // ['Eve', 'Dave', 'Frank']

// Non-mutating sort (ES2023 toSorted)
const original = [3, 1, 2];
const sorted = original.toSorted((a, b) => a - b);
console.log(original); // [3, 1, 2] — unchanged
console.log(sorted);   // [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

reverse()

const arr = [1, 2, 3, 4, 5];
arr.reverse(); // mutates in place
console.log(arr); // [5, 4, 3, 2, 1]

// Non-mutating (ES2023 toReversed)
const original = [1, 2, 3];
const reversed = original.toReversed();
console.log(original); // [1, 2, 3] — unchanged
Enter fullscreen mode Exit fullscreen mode

Adding and Removing Elements

push(), pop(), shift(), unshift()

const stack = [];
stack.push(1, 2, 3); // Add to end
console.log(stack);  // [1, 2, 3]

const last = stack.pop(); // Remove from end
console.log(last);  // 3
console.log(stack); // [1, 2]

const queue = [1, 2, 3];
queue.shift();  // Remove from front — returns 1
console.log(queue); // [2, 3]

queue.unshift(0); // Add to front
console.log(queue); // [0, 2, 3]
Enter fullscreen mode Exit fullscreen mode

splice() and toSpliced()

const colors = ['red', 'green', 'blue', 'yellow'];

// Remove 2 elements starting at index 1
const removed = colors.splice(1, 2);
console.log(removed); // ['green', 'blue']
console.log(colors);  // ['red', 'yellow']

// Insert without removing
colors.splice(1, 0, 'purple', 'orange');
console.log(colors); // ['red', 'purple', 'orange', 'yellow']

// Replace 1 element at index 2
colors.splice(2, 1, 'cyan');
console.log(colors); // ['red', 'purple', 'cyan', 'yellow']

// Non-mutating (ES2023)
const original = [1, 2, 3, 4];
const updated = original.toSpliced(1, 2, 10, 20);
console.log(original); // [1, 2, 3, 4] — unchanged
console.log(updated);  // [1, 10, 20, 4]
Enter fullscreen mode Exit fullscreen mode

slice()

slice() returns a shallow copy of a portion of the array without mutating the original.

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

console.log(arr.slice(2));     // [2, 3, 4, 5]
console.log(arr.slice(1, 4));  // [1, 2, 3]
console.log(arr.slice(-2));    // [4, 5]  (last 2 items)
console.log(arr.slice(0, -1)); // [0, 1, 2, 3, 4]  (all but last)

// Shallow copy of entire array
const copy = arr.slice();
Enter fullscreen mode Exit fullscreen mode

Combining Arrays

concat()

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [7, 8, 9];

const combined = a.concat(b, c);
console.log(combined); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// Spread operator is a modern alternative
const merged = [...a, ...b, ...c];
Enter fullscreen mode Exit fullscreen mode

Utility Methods

forEach()

forEach() executes a callback for each element but returns undefined. Use it for side effects (logging, DOM updates) — not for building new arrays.

const items = ['a', 'b', 'c'];
items.forEach((item, index) => {
  console.log(`${index}: ${item}`);
});
// 0: a
// 1: b
// 2: c
Enter fullscreen mode Exit fullscreen mode

Array.from() and Array.of()

// Create from an iterable or array-like object
const set = new Set([1, 2, 3, 2, 1]);
const unique = Array.from(set);
console.log(unique); // [1, 2, 3]

// Create from a string
const chars = Array.from('hello');
console.log(chars); // ['h', 'e', 'l', 'l', 'o']

// Create with a mapping function
const squares = Array.from({ length: 5 }, (_, i) => i ** 2);
console.log(squares); // [0, 1, 4, 9, 16]

// Array.of — unlike the Array constructor, behaves consistently
console.log(Array.of(3));     // [3]
console.log(new Array(3));    // [undefined × 3] — gotcha!
Enter fullscreen mode Exit fullscreen mode

fill()

// Initialize an array with a default value
const zeros = new Array(5).fill(0);
console.log(zeros); // [0, 0, 0, 0, 0]

// Fill a slice
const arr = [1, 2, 3, 4, 5];
arr.fill(0, 2, 4); // fill with 0 from index 2 to 4 (exclusive)
console.log(arr);  // [1, 2, 0, 0, 5]
Enter fullscreen mode Exit fullscreen mode

join()

const words = ['JavaScript', 'is', 'awesome'];
console.log(words.join(' '));  // 'JavaScript is awesome'
console.log(words.join('-'));  // 'JavaScript-is-awesome'
console.log(words.join(''));   // 'JavaScriptisawesome'
Enter fullscreen mode Exit fullscreen mode

Chaining Methods

The real power of array methods comes from chaining them. Each method returns a new array, so you can compose transformations without intermediate variables.

const transactions = [
  { type: 'debit',  amount: 250,  category: 'food'      },
  { type: 'credit', amount: 1000, category: 'salary'    },
  { type: 'debit',  amount: 80,   category: 'transport' },
  { type: 'debit',  amount: 300,  category: 'food'      },
  { type: 'credit', amount: 500,  category: 'freelance' },
];

// Total spending on food
const foodSpend = transactions
  .filter(t => t.type === 'debit' && t.category === 'food')
  .map(t => t.amount)
  .reduce((sum, amount) => sum + amount, 0);

console.log(foodSpend); // 550

// Top 3 expense amounts
const topExpenses = transactions
  .filter(t => t.type === 'debit')
  .map(t => t.amount)
  .sort((a, b) => b - a)
  .slice(0, 3);

console.log(topExpenses); // [300, 250, 80]
Enter fullscreen mode Exit fullscreen mode

Performance Considerations

Array methods are generally efficient, but a few things to keep in mind at scale:

  • Short-circuit early: Prefer find() over filter()[0] when you need one item — find() stops at the first match.
  • Avoid chaining when a single reduce() suffices: filter().map() iterates twice. A single reduce() can do both in one pass.
  • Mutating methods on large arrays: push()/pop() are O(1). shift()/unshift() are O(n) — they reindex every element. For queues, consider a pointer-based approach instead.
  • sort() is not stable in old engines: V8 guarantees a stable sort since Node.js 12. If you need sorted + stable in an old environment, use a library.

Quick Reference

// Returns a new array
arr.map(fn)           // transform each element
arr.filter(fn)        // keep matching elements
arr.slice(start, end) // copy a portion
arr.concat(...arrays) // combine arrays
arr.flat(depth)       // flatten nested arrays
arr.flatMap(fn)       // map + flatten one level

// Returns a single value
arr.reduce(fn, init)  // fold to a value
arr.find(fn)          // first matching element
arr.findIndex(fn)     // index of first match
arr.indexOf(val)      // index by value (===)
arr.includes(val)     // boolean existence check
arr.some(fn)          // any element matches?
arr.every(fn)         // all elements match?
arr.join(sep)         // to string

// Mutates the original array
arr.push(...items)    // add to end
arr.pop()             // remove from end
arr.shift()           // remove from front
arr.unshift(...items) // add to front
arr.splice(i, n, ...) // insert / remove at index
arr.sort(compareFn)   // sort in place
arr.reverse()         // reverse in place
arr.fill(val, s, e)   // fill a range

// Non-mutating ES2023 alternatives
arr.toSorted(compareFn)
arr.toReversed()
arr.toSpliced(i, n, ...)
arr.with(index, value)

// Static methods
Array.from(iterable, mapFn)
Array.of(...items)
Array.isArray(val)
Enter fullscreen mode Exit fullscreen mode

Bookmark this guide and use our developer tools for your daily workflow. Mastering these methods will make your JavaScript code more expressive, faster to write, and easier to maintain.

Free Developer Tools

If you found this article helpful, check out DevToolkit — 40+ free browser-based developer tools with no signup required.

Popular tools: JSON Formatter · Regex Tester · JWT Decoder · Base64 Encoder

🛒 Get the DevToolkit Starter Kit on Gumroad — source code, deployment guide, and customization templates.

Top comments (0)