Arrays, objects, and the methods people actually use
map, filter and reduce over a hand-written loop, and the two ways to copy an object.
After this lesson you can
- Choose between map, filter and reduce without reaching for a loop first
- Destructure an object and an array, including with defaults
- Explain what spread copies and what it does not
Three methods cover most of what a hand-written for loop over an array
is doing.
const nums = [1, 2, 3, 4];
nums.map((n) => n * 2); // [2, 4, 6, 8] — same length, transformed
nums.filter((n) => n % 2 === 0); // [2, 4] — a subset, same shape
nums.reduce((sum, n) => sum + n, 0); // 10 — collapsed to one value
map transforms every element and keeps the length. filter keeps
some elements and drops the rest. reduce folds the whole array into
one value — a sum, an object, another array, anything. Reaching for
reduce to build a new array is legal and occasionally the cleanest
option, but map/filter read better when either one alone would do.
None of the three mutate the original array. push, pop, splice and
sort do — sort in particular surprises people, because it sorts in
place and returns the same array, so const sorted = nums.sort()
quietly reorders nums too.
Destructuring
Pulling values out of an object or array by shape, instead of by
obj.property one line at a time.
const { name, email = "unknown" } = user; // email defaults if absent
const [first, , third] = [1, 2, 3]; // skip an element with a comma
const { address: { city } = {} } = user; // nested, with a fallback object
The nested default (= {}) matters: without it, a user with no
address throws trying to read .city off undefined, rather than
quietly giving city the value undefined.
Try it
export function run() { const words = ["pear", "plum", "kiwi", "fig", "date"]; return words.reduce((byLength, w) => { (byLength[w.length] ??= []).push(w); return byLength; }, {});}Spread copies one level deep
const original = { name: "Nino", address: { city: "Tbilisi" } };
const copy = { ...original, name: "Ana" };
copy.address.city = "Batumi";
original.address.city; // "Batumi" — the same nested object, not a copy
{ ...original } creates a new top-level object, but every value that
was itself an object is copied by reference, not cloned. This is a
shallow copy, and it is the correct default — a genuine deep copy is
rarely what you actually want, and it is easy to reach for
structuredClone(value) on the rare occasion it is.
Try it yourself
2 visible tests · 2 hidden testsImplement cheapestTwo(products). Each product is
{ name, price }. Return the name of the two cheapest products,
cheapest first, as an array of two strings. Do not mutate the input
array. Assume there are always at least two products and no ties.
cheapestTwo([{"name":"Pen","price":1.2},{"name":"Notebook","price":3.5},{"name":"Desk lamp","price":24}])cheapestTwo([{"name":"A","price":1},{"name":"B","price":2}])
Sign up to check the hidden tests and save your progress. Sign up