Finally, let's put arrays to work. Arrays come with methods for processing their elements one by one.

const prices = [100, 200, 300];

prices.forEach((price) => {
  console.log(price);
});

forEach hands each value of the array to price in turn.

It does. (price) => { ... } is an arrow function — another way to write a function. Like function, it has an input and a body, but you can pass it inline without naming it.

So we are passing a function to a function.

Exactly. forEach is the entry point for saying "do this to each element".

When you want a new array built from the old one, use map.

const prices = [100, 200, 300];
const doubledPrices = prices.map((price) => price * 2);

console.log(doubledPrices);
console.log(prices);

[200, 400, 600] and [100, 200, 300]. The original is untouched.

An important property. map returns its result as a new array, so the original data survives and chains of processing stay easy to follow.

To keep only the elements that match a condition, use filter.

const scores = [45, 82, 68, 91];
const passedScores = scores.filter((score) => score >= 60);

console.log(passedScores);

Only elements where the function returned true remain. That is the comparison from chapter 3, used here.

Good eye. filter evaluates the condition for each element and collects the ones that came out true into a new array.

Types carry through as well. scores is number[], so score is a number — which is why no annotation is needed here.

Variables, arithmetic, conditions, functions, arrays, types — they all connect.

That was the whole aim. New syntax is far easier to read as a combination of things you already know than as something to memorize on its own.

When you meet code you do not understand, trace it in order: what is the value, where did it get its name, which function does it go to, and what comes back. That way of reading works on any program.