Module: JavaScript
JavaScript·052·4 MIN READ

052: Arrays and Indexed Collections

TOPICS COVERED: Arrays and Indexed Collections

Outcomes

By the end of this lesson, you can:

  • create arrays with literal syntax;
  • read and replace elements by zero-based index;
  • use length and calculate the last valid index;
  • explain array mutation and constant bindings;
  • add and remove end elements at an introductory level;
  • traverse an array safely; and
  • access values in a nested array.

Prerequisites and Retrieval

Retrieve types, loops, functions, and callback basics.

  1. What does Array.isArray(value) answer?
  2. Why can an array bound to const still change internally?
  3. What loop condition safely traverses all array indexes?

053 studies specific mutation and copying methods in depth. Today builds the collection mental model first.

Terms

  • array: Ordered collection of values with length and index access. — Source: MDN: Array
  • element: A value stored at some position within an array. — Source: MDN: Array
  • index: Zero-based position of an element inside an array. — Source: MDN: Array
  • array literal: [a, b, c] notation creating an array directly. — Source: MDN: Array
  • length: Property holding the element count; writable with surprising effects. — Source: MDN: Array.length
  • mutation: Modifying the array in place (push, splice, sort). — Source: MDN: Glossary — Mutable
  • reference: Copyable pointer to the same underlying array/object. — Source: MDN: Data structures
  • dense array: Array containing a value at every index through length-1. — Source: MDN: Array
  • sparse array: Array with holes — missing indices between elements. — Source: MDN: Sparse arrays
  • nested array: An array stored as an element of another array. — Source: MDN: Array
  • Array (official): "An array is an ordered list of values, indexed from 0." — Source: MDN: Array
  • Mutation vs Copy: "Mutation changes the original object; copying creates a new object with the same data." — Source: MDN: Mutating vs non-mutating methods

Beginner Explanation and Mental Model

An array is an ordered row of labeled positions. The labels are numeric indexes starting at zero:

js
const subjects = ["HTML", "CSS", "JavaScript"];
// indexes:          0      1          2

Use bracket notation to read an element:

js
console.log(subjects[0]); // HTML
console.log(subjects[2]); // JavaScript

Why zero? JavaScript follows a common programming convention in which an index is an offset from the start. The first value is zero positions away. Do not subtract one when accessing a known index. Do subtract one from length to calculate the final valid index:

js
const lastIndex = subjects.length - 1;
console.log(subjects[lastIndex]); // JavaScript

For a dense array, length is the number of elements. Reading an out-of-range index returns undefined; it does not throw:

js
console.log(subjects[99]); // undefined

That can hide an off-by-one bug, so verify the index rather than treating undefined as proof that the data is absent.

Creating and changing arrays

Prefer array literal syntax:

js
const tasks = ["Plan", "Code", "Test"];
const emptyList = [];

Literal syntax avoids the confusing difference between [3] (one element equal to 3) and Array(3) (length 3 with empty slots).

Replace an element by assignment:

js
tasks[1] = "Build";

Add and remove at the end:

js
tasks.push("Review");
const removedTask = tasks.pop();

Both methods mutate the existing array. push() returns the new length; pop() returns the removed value or undefined for an empty array. Their full comparison with front operations and copying methods comes tomorrow.

The binding can remain const because it still identifies the same array:

js
const skills = ["HTML"];
skills.push("CSS"); // mutation is allowed
// skills = ["JavaScript"]; // reassignment is not allowed

References

Assigning an array to another variable does not clone it:

js
const firstList = ["A"];
const secondName = firstList;
secondName.push("B");
console.log(firstList); // ["A", "B"]

Both bindings refer to one array. Make mutation choices explicit so callers are not surprised.

Worked Example: Task List

js
const tasks = ["Read lesson", "Write notes", "Practice code"];

console.log("Task count:", tasks.length);
console.log("First task:", tasks[0]);
console.log("Last task:", tasks[tasks.length - 1]);

tasks[1] = "Summarize notes";
tasks.push("Review mistakes");

console.log("Updated tasks:");
for (let index = 0; index < tasks.length; index += 1) {
  const position = index + 1;
  console.log(`${position}. ${tasks[index]}`);
}

const completedTask = tasks.pop();
console.log("Removed from end:", completedTask);
console.log("Remaining count:", tasks.length);

Expected output:

text
Task count: 3
First task: Read lesson
Last task: Practice code
Updated tasks:
1. Read lesson
2. Summarize notes
3. Practice code
4. Review mistakes
Removed from end: Review mistakes
Remaining count: 3

The display position is index + 1 for human-friendly numbering, but access still uses the actual zero-based index. After push, length changes from 3 to 4. After pop, it returns to 3. const tasks remains valid throughout because the binding is never replaced.

Intermediate Example: Product Stock Summary

Arrays may hold any values, including small product arrays. Objects are taught later, so represent each product as [name, price, stock]:

js
const products = [
  ["Notebook", 80, 5],
  ["Pen", 20, 0],
  ["Folder", 50, 3],
];

let inventoryValue = 0;

for (const product of products) {
  const name = product[0];
  const price = product[1];
  const stock = product[2];
  const productValue = price * stock;

  inventoryValue += productValue;
  console.log(`${name}: ${stock} in stock, value ${productValue}`);
}

console.log("Inventory value:", inventoryValue);
console.log("Second product name:", products[1][0]);

Expected output:

text
Notebook: 5 in stock, value 400
Pen: 0 in stock, value 0
Folder: 3 in stock, value 150
Inventory value: 550
Second product name: Pen

products[1] selects the second nested array; [0] then selects its first element. Nested arrays are useful for grids and compact structures, but positional meaning becomes hard to remember. Objects will later provide names such as product.price.

Optional Advanced Extension: Copying the Outer Array

slice() with no arguments creates a shallow outer-array copy:

js
const original = ["HTML", "CSS"];
const copy = original.slice();
copy.push("JavaScript");

console.log(original); // ["HTML", "CSS"]
console.log(copy);     // ["HTML", "CSS", "JavaScript"]
console.log(original === copy); // false

"Shallow" matters for nested arrays: the outer array is new, but inner-array references are shared. Do not claim this is a deep clone. 053 uses slice mainly for selecting ranges.

Mistakes and Debugging

  • Starting at index 1: the first element is index 0.
  • Using array[array.length] for the last item: that position is immediately after the last; use length - 1.
  • Using <= array.length in traversal: use < array.length.
  • Confusing position and index: human item 1 has index 0.
  • Reassigning a constant array: mutate deliberately or create a new constant with a copy.
  • Expecting assignment to clone: two bindings then share one array.
  • Creating gaps: assigning items[10] to a short array creates empty slots. Prefer normal append operations.
  • Using delete items[index]: it leaves an empty slot and does not reduce length. Use array methods such as splice tomorrow.
  • Mixing unrelated types: JavaScript permits it, but homogeneous collections are easier to process.

Inspect arrays with console.log(items), items.length, and explicit indexes. Some consoles display a later view of a referenced array; logging items.slice() captures a shallow snapshot of the outer array for clearer debugging.

Best Practices

  • Prefer const for an array binding and literal [] syntax.
  • Use plural names for collections and singular names for current elements.
  • Keep arrays dense and usually hold values with a consistent meaning.
  • Calculate last index as length - 1; handle empty arrays before using it.
  • Use for...of when only values matter and an indexed loop when the index matters.
  • Do not mutate arrays unexpectedly inside reusable functions.
  • Capture return values from removing operations when they matter.
  • Choose objects later when nested positions become cryptic.

Tiered Exercises

Core

Create an array of four colors. Log its length, first value, third value, and last value. Replace the second color, append one color, then print every color with its index.

Practice

Manage ["plan", "code", "test"]: replace "code" with "build", append "deploy", remove and store the last task, and print the remaining list and removed task.

Professional Extension

Create a 3 by 3 number grid as nested arrays. Use nested loops to print every coordinate and value, then calculate the total of all values.

Complete Solutions

js
const colors = ["red", "green", "blue", "yellow"];
console.log(colors.length);            // 4
console.log(colors[0]);                // red
console.log(colors[2]);                // blue
console.log(colors[colors.length - 1]); // yellow

colors[1] = "purple";
colors.push("orange");

for (let index = 0; index < colors.length; index += 1) {
  console.log(index, colors[index]);
}
js
const tasks = ["plan", "code", "test"];
tasks[1] = "build";
tasks.push("deploy");
const removedTask = tasks.pop();

console.log(tasks);       // ["plan", "build", "test"]
console.log(removedTask); // deploy
js
const grid = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

let total = 0;
for (let row = 0; row < grid.length; row += 1) {
  for (let column = 0; column < grid[row].length; column += 1) {
    const value = grid[row][column];
    console.log(`(${row}, ${column}) = ${value}`);
    total += value;
  }
}
console.log("Total:", total); // 45

Recap and Exit Questions

Arrays are ordered, zero-indexed collections. length describes their index range, bracket notation accesses elements, and mutation changes the existing collection. A constant binding does not make array contents immutable, and nested arrays require one index per level.

  1. What is the last valid index of an array with length 5?
  2. What happens when an out-of-range index is read?
  3. How do reassignment and mutation differ?
  4. Why does assigning an array to another variable not clone it?
  5. How do you access the second value in the first nested row?

Official References

References checked 2026-08-24.