Arrays and objects
Many values under one name: lists in order, records with named fields, and the two or three methods worth knowing.
An array is a list in order
const loaves = ["white", "rye", "focaccia"]; builds an array. Items have positions, counted from zero, and loaves[0] is the first. loaves.length counts them, and loaves.push("spelt") adds to the end.
Arrays keep their order, which is the point when order matters — a queue of steps, a list of names as typed. When you reach for one by position, you are using an array the way it is meant to be used.
The position is the distance from the start, which is why the first item is at zero. That is a rule about counting, not about the data: the array does not know what the items mean. When the meaning matters more than the position, an object is the better shape.
Walking, adding, and building a new list
const loaves = ["white", "rye", "focaccia"];
for (const loaf of loaves) {
console.log(loaf.toUpperCase());
}
loaves.push("spelt");
console.log(loaves.length);
const lengths = loaves.map((loaf) => loaf.length);
console.log(lengths);map builds a new array
map runs a function on every item and collects the results into a new array of the same length — one line instead of a loop with an empty array and a push. filter keeps the items a function says yes to; find returns the first one that matches.
The original array is never changed by these. That is deliberate: building a new value from an old one is easier to follow than editing a list in place, and it leaves the original available for whatever else needs it.
An object is a record with names
An object groups related values under names: { name: "Rye", minutes: 40 }. Reach for a field with a dot — recipe.name — and set one with an assignment: recipe.minutes = 45.
Use an array when the order is the point and an object when the names are. A list of recipes is an array; one recipe is an object; and an array of objects is what most real data turns out to be.
A field can hold anything: a string, a number, an array, another object. That nesting is what lets one value describe a whole record, and it is why a shallow copy is not always enough. Reading a missing field gives undefined, so a typo in a property name stays silent until the value is used.
A name points at a list, it does not hold it
Arrays and objects are reference values. const first = [1, 2]; const second = first; does not make a second list — it makes a second name for the same one. Push into second and first changes too, because there is only one array and both names lead to it.
A real copy is made deliberately: const second = [...first]; for an array, { ...recipe } for an object. The copy is shallow, so nested objects are still shared — enough for a flat list, and worth knowing before changing something two levels down.
The methods that change, and the methods that answer
Some array methods change the array they are called on: push, pop, splice and reverse. Others answer with a new array and leave the original alone: map, filter, slice and concat. Reading which is which prevents a surprising amount of "why did my other list change?" debugging.
sort belongs to the first group and has a second surprise: without a comparator it sorts as text, so 10 comes before 9. Give it (a, b) => a - b for numbers. And reading a field that does not exist gives undefined rather than an error, so a misspelled property quietly becomes a blank in the output.
A worked map and filter
Take recipes with three objects. recipes.map((recipe) => recipe.name) calls the function once per object and collects the three names into a new array, in the same order. recipes.filter((recipe) => recipe.minutes < 45) keeps the objects where the answer is true, so the result may be shorter than the input.
Chaining them is where the shape becomes clear: recipes.filter(...).map(...) first narrows the list, then turns each survivor into a name. The original array is untouched at every step, so the same list can feed two reports without either disturbing the other.
Three mistakes worth avoiding: const copy = list aliases rather than copies; list.sort() sorts numbers as text unless you pass (a, b) => a - b; and a misspelled property name returns undefined instead of throwing, so the mistake shows up later as a missing value rather than at the typo.
Try these next
- Copy an array with spread, change the copy, and log both to prove the original is untouched.
- Sort
[10, 9, 100]once without a comparator and once with(a, b) => a - b. - Filter a list of recipes by time, then map the survivors to their names.
A list of recipes, and one of their names
Add a fourth recipe with push, then log every recipe’s name — the whole list, and then a new array of just the names built with map.
3 left to do
- A recipe is added with push
- The names are collected with map
- Something is logged
The array holds objects; each has a name field. recipes.map((recipe) => recipe.name) builds the list of names.
The quick ones, and their total time
From the recipe list, collect the names of every recipe that takes less than 45 minutes, then add up the time of just those recipes. Log both the names and the total.
3 left to do
- The quick recipes are filtered out
- Their minutes are added up
- The names and total are logged
recipes.filter((recipe) => recipe.minutes < 45) keeps the quick ones. map turns them into names, and reduce adds their minutes with a starting value of 0.
push changes the array it belongs to, while map and filter hand you a new one. Knowing which of the two a method does saves a surprising amount of debugging.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
Which item is loaves[0]?
