JavaScriptArrays

Arrays

An array is JavaScript's built-in ordered list. It holds a sequence of values — numbers, strings, objects, other arrays, even functions — accessible by a numeric index that starts at 0. Arrays are the workhorse data structure of the language: you'll model rows, lists, queues, stacks, paths, history and just about anything sequential with them.

Creating arrays

The literal form with square brackets is the one you should reach for ninety-nine times out of a hundred.

JS
const empty = [];
const nums = [1, 2, 3];
const mixed = [1, "two", true, null, { id: 4 }, [5, 6]];

// The Array constructor exists, but the literal is clearer.
const fromCtor = new Array(1, 2, 3);   // [1, 2, 3]
const sized    = new Array(3);         // length 3, but EMPTY slots
const filled   = Array.from({ length: 3 }, (_, i) => i); // [0, 1, 2]
const of       = Array.of(3);          // [3]  (not "length 3")
new Array(n) is a footgun
`new Array(3)` creates an array of length 3 with *no* elements — its indices are holes, not `undefined`. Most methods skip those holes. Use `Array.from({ length: n })` or `[].fill(v, 0, n)` when you actually want a populated array.
Indexing and length

Indices start at zero. The length property is one greater than the highest set index — and it is writable, which is one of the language's stranger corners.

JS
const fruits = ["apple", "banana", "cherry"];

fruits[0];           // "apple"
fruits[2];           // "cherry"
fruits[99];          // undefined  (not an error)
fruits.length;       // 3

fruits[5] = "fig";   // assigning past the end EXTENDS the array
fruits.length;       // 6  (indices 3 and 4 are holes)

fruits.length = 2;   // truncates: anything from index 2 onwards is gone
fruits;              // ["apple", "banana"]

Negative indices do not work the way they do in Python. fruits[-1] is treated as the property "-1" and returns undefined. Use arr.at(-1) instead — see the next page on array methods.

Reading, writing, iterating

JS
const colors = ["red", "green", "blue"];

// Classic index loop
for (let i = 0; i < colors.length; i++) {
  console.log(i, colors[i]);
}

// for...of — values
for (const c of colors) {
  console.log(c);
}

// entries() — index + value
for (const [i, c] of colors.entries()) {
  console.log(i, c);
}
0 red
1 green
2 blue

Avoid for...in on arrays. It iterates all enumerable string keys — including ones added to Array.prototype by older libraries — and gives you indices as strings rather than numbers.

Sparse arrays (holes)

A sparse array has gaps — indices that were never assigned. Holes are not the same as undefined: most array methods ignore them, but a few (like Array.from) materialise them as undefined.

JS
const sparse = [1, , 3];        // index 1 is a hole
sparse.length;                  // 3
sparse[1];                      // undefined (reading a missing prop)

sparse.forEach(v => console.log(v));      // 1, 3   (skips the hole)
sparse.map(v => v ?? "?");                // [1, <empty>, 3]
Array.from(sparse, v => v ?? "?");        // [1, "?", 3]  (no holes)
Avoid sparse arrays
They are confusing, behave inconsistently across methods, and disable some engine optimisations. If you need "missing" slots, use `null` or `undefined` explicitly so every method sees the same data.
Arrays are objects

Under the hood an array is an object. The numeric "indices" are really string keys ("0", "1", "2"). That has two consequences worth knowing:

  • You can attach non-numeric properties to an array, but they do not affect length and most array methods will ignore them. It is almost always a sign you should use a regular object instead.

  • typeof [] is "object". Use Array.isArray(value) to test specifically for an array — it works across iframes and is the standard answer.

JS
const list = [10, 20, 30];
list.note = "do not lose this";   // legal but weird

list.length;                       // 3  (the note doesn't count)
typeof list;                       // "object"
Array.isArray(list);               // true
Array.isArray({ length: 0 });      // false  (just an object that looks array-ish)
Arrays vs plain objects — when to use what

The two are interchangeable for some tasks; you can store rows in an object keyed by id, or fields in an array of pairs. A small decision table helps:

  • Use an array when order matters and you mostly iterate or push/pop. Examples: a list of todos, a search result page, a queue of jobs.

  • Use an object (or a Map) when lookup by key matters and the order does not. Examples: caching responses by URL, user records keyed by id.

  • Arrays let you use methods like map, filter, reduce, sort. Plain objects do not — you have to go via Object.entries first.

  • JSON arrays serialise their elements; JSON objects serialise key/value pairs. The choice flows from the data, not from style.

Copying and the reference trap

Assignment copies a reference, not the array. Two variables can point at the same underlying list.

JS
const a = [1, 2, 3];
const b = a;
b.push(4);
a;                    // [1, 2, 3, 4]  — same array!

const c = [...a];     // shallow copy
c.push(5);
a;                    // [1, 2, 3, 4]
c;                    // [1, 2, 3, 4, 5]

[...a] (spread) and a.slice() both make a shallow copy — one level deep. Nested arrays and objects are still shared. For a deep copy, use structuredClone(a) in modern environments.

A quick mental model
  • An array is an ordered collection accessed by zero-based index.

  • length is writable and shrinks or extends the array.

  • Assigning past the end creates holes — avoid this on purpose.

  • Arrays are objects, but Array.isArray is the right type check.

  • Spread or slice for shallow copies; structuredClone for deep ones.

The next page tours the built-in methods — push, pop, slice, concat, flat and friends — that turn the basic structure above into a productive toolkit.