More Array Methods

We have seen the main transformation and search methods. JavaScript arrays have several more methods that come up in everyday work.

forEach: Iteration with Side Effects

The forEach method executes a function for each element but does not return anything:

const numbers = [1, 2, 3];

numbers.forEach((n) => console.log(n));
// 1
// 2
// 3

Use forEach when you need side effects (logging, updating external state) rather than transforming data:

const cart = [
  { name: "Apple", price: 1.5 },
  { name: "Banana", price: 0.75 },
];

let total = 0;
cart.forEach((item) => {
  total += item.price;
});
console.log(total);  // 2.25

flat: Flatten Nested Arrays

The flat method creates a new array with nested arrays flattened:

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));  // Flatten all levels

This is useful when the data is grouped:

const departments = [
  { name: "Engineering", employees: ["Alice", "Bob"] },
  { name: "Sales", employees: ["Charlie", "Diana"] },
];

const allEmployees = departments.map((d) => d.employees).flat();
console.log(allEmployees);  // ['Alice', 'Bob', 'Charlie', 'Diana']

flatMap: Map Then Flatten

The flatMap method combines map and flat(1) in one step:

const sentences = ["Hello world", "How are you"];

const words = sentences.flatMap((s) => s.split(" "));
console.log(words);  // ['Hello', 'world', 'How', 'are', 'you']

// Equivalent to:
const words2 = sentences.map((s) => s.split(" ")).flat();

It is useful when your map function returns arrays:

const users = [
  { name: "Alice", hobbies: ["reading", "gaming"] },
  { name: "Bob", hobbies: ["cooking"] },
];

const allHobbies = users.flatMap((u) => u.hobbies);
console.log(allHobbies);  // ['reading', 'gaming', 'cooking']

sort: Ordering Elements

The sort method sorts an array in place and returns it:

const fruits = ["banana", "apple", "cherry"];
fruits.sort();
console.log(fruits);  // ['apple', 'banana', 'cherry']

Warning: Default sort converts elements to strings, which sorts numbers in lexicographic order instead of numeric order:

const numbers = [10, 2, 5, 1, 9];
numbers.sort();
console.log(numbers);  // [1, 10, 2, 5, 9] - Wrong!

Provide a compare function for correct numeric sorting:

const numbers = [10, 2, 5, 1, 9];
numbers.sort((a, b) => a - b);  // Ascending
console.log(numbers);  // [1, 2, 5, 9, 10]

numbers.sort((a, b) => b - a);  // Descending
console.log(numbers);  // [10, 9, 5, 2, 1]

Sorting objects by a property:

const users = [
  { name: "Charlie", age: 25 },
  { name: "Alice", age: 30 },
  { name: "Bob", age: 20 },
];

users.sort((a, b) => a.age - b.age);
console.log(users.map((u) => u.name));  // ['Bob', 'Charlie', 'Alice']

reverse: Reversing Order

The reverse method reverses an array in place:

const letters = ["a", "b", "c"];
letters.reverse();
console.log(letters);  // ['c', 'b', 'a']

Like sort, it mutates the original array. Use toReversed() (ES2023) or [...array].reverse() for a non-mutating version.

slice: Extracting Portions

The slice method returns a shallow copy of a portion of an array:

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

console.log(numbers.slice(2));  // [2, 3, 4, 5] - from index 2
console.log(numbers.slice(1, 4));  // [1, 2, 3] - from 1 to 4 (exclusive)
console.log(numbers.slice(-2));  // [4, 5] - last 2 elements
console.log(numbers.slice(0, -1));  // [0, 1, 2, 3, 4] - all but last

slice does not modify the original array, so we can use it to make a copy:

const copy = numbers.slice(); // Full copy

concat: Combining Arrays

The concat method merges arrays without modifying the originals:

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

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

The spread operator is often shorter for this:

const combined = [...a, ...b, ...c];

Method Chaining Summary

These methods can be chained together into a data pipeline:

const orders = [
  { product: "Laptop", amount: 999, status: "shipped" },
  { product: "Phone", amount: 699, status: "pending" },
  { product: "Tablet", amount: 449, status: "shipped" },
  { product: "Watch", amount: 299, status: "shipped" },
];

const shippedTotal = orders
  .filter((o) => o.status === "shipped")
  .map((o) => o.amount)
  .reduce((sum, amount) => sum + amount, 0);

console.log(shippedTotal);  // 1747