JavaScript

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

Reduce building a lookup, not a sumnode-22
export function run() {  const words = ["pear", "plum", "kiwi", "fig", "date"];  return words.reduce((byLength, w) => {    (byLength[w.length] ??= []).push(w);    return byLength;  }, {});}
What to look for

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 tests

Implement 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}])
Loading editor…

Sign up to check the hidden tests and save your progress. Sign up