Command Palette

Search for a command to run...

Hectal
PHASE 5Beginner ~24 min· topic 1 of 10

Topic 5.1

Creating and Reading Arrays

In one line

An array is an ordered list of values; you create one with square brackets, read items by their position number (the index, starting at 0), get the count from length, and build arrays from other things with Array.from and Array.of.

Think of it like this

A row of numbered lockers at a swimming pool. The row has one name ("the blue lockers"), and each locker has a number painted on the door, starting at 0. To get your bag you say "locker 2", not "the third one from the left". The sign at the end says how many lockers there are. An array is that row: one name, numbered slots, and a count.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Array
An ordered list of values stored under one name.
Element (item)
One value inside an array.
Index
The position number of an element. The first one is 0, not 1.
length
The number of slots in the array: one more than the last index.
Array literal
An array written directly in code with square brackets, like [1, 2, 3].
Sparse array
An array with holes: empty slots that hold no value at all.
Iterable
Something you can loop over with for...of, such as an array, a string, a Set or a Map.
Array-like
An object that has a length and numbered keys but isn't a real array, such as a NodeList.
Reference
What a variable really holds for an array: a pointer to the one array in memory, not a copy.

Step by step

01Make an array

Square brackets, items separated by commas. A comma after the last item (a trailing comma) is allowed and makes adding lines easier.

app.jswhole filejavascript
const pets = [
  "cat",
  "dog",
  "fish",
];
console.log(pets.length); // 3

02Read by index

Counting starts at 0, so three items have the indexes 0, 1 and 2. The last index is always length - 1.

Read by indexdiagram
Rendering diagram…

03Read from the end

pets[pets.length - 1] works everywhere. pets.at(-1) says the same thing more clearly.

app.jswhole filejavascript
console.log(pets[pets.length - 1]); // fish
console.log(pets.at(-1));            // fish
console.log(pets[-1]);               // undefined

04Change an item

Assigning to an index replaces that slot. The variable is const, but the array it points to can still change.

app.jswhole filejavascript
pets[1] = "parrot";
console.log(pets); // [ 'cat', 'parrot', 'fish' ]

05Build an array from something else

Array.from turns strings, sets and page lists into real arrays, so you can use every array method on them. Pass a function as the second argument to change each item as it's copied.

app.jswhole filejavascript
Array.from("abc");                       // [ 'a', 'b', 'c' ]
Array.from({ length: 3 }, (_, i) => i + 1); // [ 1, 2, 3 ]
Array.of(3);                              // [ 3 ]

Try it yourself

  1. 1

    Read from the end

    In the first example, predict what fruits.at(-2) and fruits.at(-4) print. Add both lines and run.

  2. 2

    Make a times table

    In the second example, change the Array.from({ length: 4 }, ...) line so it prints [ 7, 14, 21, 28, 35 ]. You need to change the length and the formula (remember i starts at 0).

  3. 3

    Grow by writing length

    In the third example, add nums.length = 7; at the end and log nums. Predict how many <empty> slots you'll see.

Code & diagrams

Create, read and count ES2022+ New tab

`at()` is ES2022; everything else here has worked since the first versions of JavaScript. The page uses an `<ol>`, which numbers from 1, while the indexes start at 0.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

[ 'apple', 'banana', 'cherry' ]
3
apple cherry
undefined
cherry
cherry
undefined
Array.from, Array.of and the Array(n) trap ES2015+ New tab

Hectal's console shows each hole as `<empty>`. Chrome's DevTools shows `[empty × 3]` and Node.js shows `[ <3 empty items> ]`: same thing.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

[ 7 ]
7
[ <empty>, <empty>, <empty> ]
[ 'h', 'i', '!' ]
[ 0, 10, 20, 30 ]
[ 3, 1 ]
false true
[ 'Tea', 'Coffee' ]
length can be written, and arrays are objects New tab

Setting `length` smaller deletes items for good. Writing past the end leaves holes. `const` only protects the variable, not the array's contents.

Console

(nothing was printed)

Expected console output

[ 1, 2 ]
[ 1, 2, <empty>, <empty>, 9 ] 5
object true
[ 'allowed' ]

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Off by one at the end

Loop with i <= fruits.length instead of i < fruits.length.

terminal
$ the page shows
── what you'll see ──
A fourth list item reading "index 3: undefined".

Break #2

Array(3) instead of [3]

Write const ids = new Array(3); meaning "an array containing 3", then console.log(ids[0]);.

terminal
$ Console
── what you'll see ──
undefined

Myth vs fact

Myth

arr[-1] gives the last element, like in Python.

Fact

In JavaScript it is undefined: -1 is looked up as an ordinary property name. Use arr.at(-1) or arr[arr.length - 1].

Myth

A const array can't be changed.

Fact

const means the variable always points at the same array. You can still add, remove and replace items inside it. To stop changes to the contents, use Object.freeze(arr) (Phase 6).

Myth

Reading outside the array throws an error.

Fact

It returns undefined, quietly. That's why off-by-one bugs in JavaScript often don't crash; they show undefined somewhere instead.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Engines like V8 store arrays in fast internal forms called elements kinds: packed small integers, packed doubles, or general values. Mixing types or making holes moves an array to a slower kind, and it never moves back. new Array(1000) starts holey; building with push or Array.from keeps it packed.

  • ▸

    Array indexes are really property keys, converted to strings: arr["1"] and arr[1] are the same slot. Only keys that are whole numbers from 0 to 2³² − 2 count as indexes and affect length; arr[-1] = "x" creates a normal property that length ignores.

  • ▸

    Array.from works on any iterable, so it understands Unicode properly: Array.from("👍🏽").length counts code points, while "👍🏽".length counts UTF-16 code units. (Phase 1 covers strings and Unicode.)

  • ▸

    The maximum array length is 2³² − 1 (4,294,967,295). Typed arrays (Uint8Array, Float64Array) are a separate family with a fixed length and one numeric type, used for binary data and graphics.

Remember this

  1. 1

    An array is a value that holds an ordered list of other values. You write one with square brackets and commas: const scores = [90, 75, 60];. This is called an array literal (a value written directly in the code). The values inside are called elements or items, and they can be any type, even mixed: [1, "two", true, null, [3]]. In practice, keep one kind of thing per array; mixed arrays are harder to work with.

  2. 2

    Each element has an index: its position number, starting at 0. scores[0] is 90, scores[1] is 75. Reading an index that doesn't exist does not throw an error: scores[10] is undefined. The length property is the number of slots, so the last element is at scores[length - 1]. Negative numbers in brackets don't count from the end: scores[-1] is undefined, because -1 is treated as an ordinary property name.

  3. 3

    at(index) (ES2022) reads an element and does accept negative numbers: scores.at(-1) is the last item, scores.at(-2) the one before. It's the clean way to read from the end. For positive numbers it behaves like brackets.

  4. 4

    length is not just a count you read; you can write it. Setting arr.length = 2 cuts the array down to two elements (the rest are deleted). Writing to an index past the end, like arr[5] = "x" on a 3-item array, makes the array longer and leaves holes: empty slots that hold nothing at all (not even undefined). Arrays with holes are called sparse; avoid creating them.

  5. 5

    Array.from(thing, mapFn?) (ES2015) builds a real array from anything iterable (something you can loop over, like a string or a Set) or array-like (an object with length and numbered keys, like the NodeList that document.querySelectorAll returns). The optional second argument changes each item on the way in: Array.from({ length: 3 }, (_, i) => i * 2) gives [0, 2, 4]. Array.of(7) (ES2015) makes [7]; it exists because Array(7) and new Array(7) mean something else: an empty array with length 7 (seven holes).

  6. 6

    Arrays are a special kind of object (Phase 6): typeof [] === "object". To check whether a value really is an array, use Array.isArray(value). And because arrays are objects, a variable holds a reference to the array (an arrow pointing at it), not the array itself. const stops you pointing the variable at a different array, but you can still change the items inside: const list = []; list[0] = 1; is allowed.

Explain it without notes

01

Why do arrays start at index 0, and how do you safely read the last element?

02

What is the difference between Array(3), Array.of(3) and [3]?

03

What does Array.from accept, and why is it useful with querySelectorAll?

04

How do you check whether a value is an array, and why doesn't typeof work?

Practice

01

Create an array of five weekdays. Print the first day, the last day using at, and the number of days.

02

Use Array.from to build an array of the squares of 1 to 5: [ 1, 4, 9, 16, 25 ].

03

Given const word = "level";, make an array of its letters and print the middle letter using length.

Trade-offs

  • ↔

    arr.at(-1) reads better than arr[arr.length - 1], but needs a 2022-or-later browser; both are equally fast.

  • ↔

    Array.from(nodes) and [...nodes] do the same for iterables; Array.from also handles array-like objects without an iterator and can map in the same pass.

Done when you can

  • I can create an array and read any element by its index.

  • I can read the last element with at(-1) or length - 1.

  • I know that reading a missing index gives undefined, not an error.

  • I can turn a string, a Set or a NodeList into an array with Array.from.

  • I can explain why Array(3) is not [3].

  • I check for arrays with Array.isArray.