⚡JavaScript
Lesson 29 of 117
35 min
Arrays Deep
map, filter, reduce, find, some, every, flat, group, immutable copies.
Arrays are how JS holds an ordered list of anything. The reason modern JS feels so different from older code is the explosion of array methods. Once you internalize map, filter, and reduce, you stop writing for-loops for almost every data task.
Making and reading arrays
js
const fruits = ["apple", "pear", "kiwi"];
fruits.length // 3
fruits[0] // "apple"
fruits[fruits.length - 1] // "kiwi" (last)
fruits.at(-1) // "kiwi" - negative index, ES2022
fruits.at(0) // "apple"
fruits.includes("pear") // true
fruits.indexOf("kiwi") // 2
fruits.indexOf("missing") // -1Use .at() for negative indexing
Older code does
arr[arr.length - 1]. .at(-1) is shorter and works for any negative offset.The three you'll use every day
map: transform each item
js
const nums = [1, 2, 3, 4];
const doubled = nums.map(n => n * 2);
// [2, 4, 6, 8]
const users = [{ name: "Ada" }, { name: "Grace" }];
const names = users.map(u => u.name);
// ["Ada", "Grace"]filter: keep some items
js
const nums = [1, 2, 3, 4, 5];
const evens = nums.filter(n => n % 2 === 0);
// [2, 4]
const users = [{ name: "Ada", active: true }, { name: "Bob", active: false }];
const active = users.filter(u => u.active);
// [{ name: "Ada", active: true }]reduce: roll the array into one value
js
const nums = [1, 2, 3, 4];
const total = nums.reduce((sum, n) => sum + n, 0);
// 10
// reduce can build any shape, not just numbers
const items = ["apple", "pear", "apple", "kiwi", "pear", "apple"];
const counts = items.reduce((acc, item) => {
acc[item] = (acc[item] ?? 0) + 1;
return acc;
}, {});
// { apple: 3, pear: 2, kiwi: 1 }Object.groupBy beats this reduce
Modern JS has
Object.groupBy (ES2024) for exactly this pattern. See below.Search methods: find, findLast, some, every
js
const users = [
{ id: 1, name: "Ada", active: true },
{ id: 2, name: "Bob", active: false },
{ id: 3, name: "Cleo", active: true },
];
users.find(u => u.id === 2);
// { id: 2, name: "Bob", ... }
users.findLast(u => u.active);
// { id: 3, name: "Cleo", ... }
users.some(u => !u.active); // true - at least one inactive?
users.every(u => u.id > 0); // true - all positive?flat and flatMap
js
[1, [2, [3, [4]]]].flat(); // [1, 2, [3, [4]]]
[1, [2, [3, [4]]]].flat(Infinity); // [1, 2, 3, 4]
// flatMap = map + flat(1). Useful for "fan out"
const sentences = ["hi there", "how are you"];
sentences.flatMap(s => s.split(" "));
// ["hi", "there", "how", "are", "you"]Object.groupBy: the new toy
ES2024 added a clean way to bucket an array by some key:
js
const transactions = [
{ id: 1, type: "debit", amount: 100 },
{ id: 2, type: "credit", amount: 200 },
{ id: 3, type: "debit", amount: 50 },
];
const grouped = Object.groupBy(transactions, t => t.type);
// {
// debit: [ {id:1,...}, {id:3,...} ],
// credit: [ {id:2,...} ],
// }Sorting without surprises
arr.sort() mutates and converts everything to strings by default. [10, 2, 1].sort() gives [1, 10, 2]. Always pass a comparator:
js
const nums = [10, 2, 30, 4];
nums.sort(); // [10, 2, 30, 4] sorted as strings: [10, 2, 30, 4]
nums.sort((a, b) => a - b); // [2, 4, 10, 30] numeric ascending
nums.sort((a, b) => b - a); // [30, 10, 4, 2] descending
const users = [{ name: "Bob" }, { name: "Ada" }];
users.sort((a, b) => a.name.localeCompare(b.name));Immutable copies: toSorted, toReversed, with
ES2023 added methods that return a new array instead of mutating in place. Way safer:
js
const nums = [3, 1, 4, 1, 5];
nums.toSorted(); // [1, 1, 3, 4, 5] - nums is unchanged
nums.toReversed(); // [5, 1, 4, 1, 3] - nums is unchanged
nums.with(0, 99); // [99, 1, 4, 1, 5] - replace index 0
nums.toSpliced(1, 2); // [3, 5] - remove 2 from index 1
// Old (mutating) versions still exist
nums.sort(); // mutates
nums.reverse(); // mutatesSpread and destructuring
js
// Spread to copy or combine
const a = [1, 2];
const b = [3, 4];
const both = [...a, ...b]; // [1, 2, 3, 4]
const copy = [...a]; // shallow clone
// Destructuring
const [first, second] = [10, 20, 30];
// first = 10, second = 20
// Skip with commas
const [, , third] = [10, 20, 30]; // third = 30
// Collect the rest
const [head, ...tail] = [1, 2, 3, 4];
// head = 1, tail = [2, 3, 4]
// Defaults
const [x = 0, y = 0] = [5]; // x = 5, y = 0Try it: transform a list of users
Quiz
Quiz1 / 4
What does [1,2,3].map(n => n * 2) return?
Recap
maptransforms,filterkeeps,reducerolls up.- Use
find/findLastfor one item,some/everyfor "any/all" tests. - Always pass a comparator to
sort. PrefertoSortedfor new arrays. - Spread copies, destructuring unpacks,
...restin destructuring collects the tail. Object.groupByand.at(-1)are modern conveniences worth memorizing.