Arrays, Iteration and Transformation

Arrays are the workhorse data structure of JavaScript. The skill is knowing which methods mutate and which copy, how to build transformation pipelines, and where the traps hide (sort, sparse arrays, spread on big data).

Arrays are ordered lists

Literals, indexes and length

An array is an ordered collection — the workhorse data structure of JavaScript. Positions start at 0; length is always one more than the last index:

const colors = ["red", "green", "blue"];
console.log(colors[0], colors.length);  // red 3
colors.push("yellow");                  // add at the end -> 4 items
colors.pop();                           // remove from the end
colors.unshift("black");                // add at the START (slow on big arrays)
console.log(colors);                    // [ 'black', 'red', 'green', 'blue' ]

Arrays are objects with number keys — typeof colors is "object"; test for a real array with Array.isArray(colors).

Mutating versus non-mutating — know which family you call

const scores = [3, 1, 2];
scores.push(4);                  // MUTATES: scores is now [3, 1, 2, 4]
console.log(scores.toSorted());  // [1, 2, 3, 4] — a COPY; original untouched
console.log(scores);             // [3, 1, 2, 4] — original order survives

The mutating classics: push/pop/shift/unshift, splice, sort, reverse. Their modern copy-first twins: toSorted, toReversed, toSpliced, with. In state-driven code (lesson 24) prefer the copies — shared arrays bite exactly like the shared objects in lesson 04's value-versus-reference diagram.

The sort trap — a runnable contraexample

const numbers = [10, 9, 100, 1];
console.log(numbers.sort());   // [ 1, 10, 100, 9 ] — sorted as TEXT!
console.log([...numbers].sort((a, b) => a - b)); // [ 1, 9, 10, 100 ] — correct

The default sort() converts items to strings and compares characters: "1" < "10" < "100" < "9". Always pass a compare function for numbers — and remember sort() mutates, hence the spread copy.

The transformation pipeline

filter → map → reduce: the workhorse chain

const orders = [
  { id: 1, total: 25,  paid: true },
  { id: 2, total: 120, paid: false },
  { id: 3, total: 80,  paid: true },
];

const revenue = orders
  .filter(order => order.paid)               // keep paid orders
  .map(order => order.total)                 // project to amounts
  .reduce((sum, amount) => sum + amount, 0); // fold into ONE number
console.log(revenue);                        // 105

Each link returns a new array (or value) — no mutation, easy to test, reads like the sentence "of the paid orders, take the totals and add them". The 0 is reduce's starting accumulator. Single-question helpers: find (first match), some (any true?), every (all true?).

When a plain loop wins

Chains run to the end; a for loop with break exits early, and complex multi-step reductions often read better as a loop. Reach for the chain first, drop to a loop when it gets in the way.

Sparse arrays — the hole trap

delete leaves a hole, not an undefined slot

const sparse = [1, 2, 3];
delete sparse[1];
console.log(1 in sparse);          // false — a HOLE, not a value
console.log(sparse.length);        // 3 — the hole still counts
console.log(sparse.map(x => "x")); // [ 'x', <1 empty item>, 'x' ] — skipped!

Holes make methods behave inconsistently (iteration skips them, length counts them). Remove items with splice/toSpliced, or write undefined explicitly instead of delete.

TypedArrays in one paragraph

Exact memory layout, fixed length

When you need raw binary — image bytes, audio, shared memory (lesson 22) — you leave normal arrays for TypedArrays: new Float32Array(8) is a fixed-length array of 8 real 32-bit numbers, backed by a contiguous buffer (ArrayBuffer). They exist so memory layout is exact; the transformation pipelines above do not apply to them directly.

Practice: the array lab

The task

Run foundations/16_arrays_lab.js with node, predicting every line — especially the sort trap. Then take the orders array and produce, in one chain, the largest paid total.

The checklist

  • You can say for any method: does it mutate or copy?
  • You can explain why [10, 9, 100, 1].sort() puts 9 last.
  • You can build a filter/map/reduce chain for a small dataset.
  • You know what delete does to an array — and what to use instead.