An array that grows
Problem
The cart is full
You are writing the shopping cart of an online store, and you keep the items in an array, as in the lesson on arrays: each item at its own index. JavaScript lets you write past the end too, but you have to keep track of the first free index. And when the customer removes an item, a hole is left:
const cart = ["Bread", "Milk", "Coffee"];
// A fourth item: we write at the first free index.cart[cart.length] = "Butter";
// The customer removes the milk.cart[1] = undefined;
for (const item of cart) { console.log(item);}console.log(cart.length);BreadundefinedCoffeeButter4undefined. And the number of items is no longer cart.length: that is 4, but there are 3 items.That is a lot of code for something every store does all the time.
The idea
push and splice: the array looks after itself
The array has methods that do this for you. It does the copying and shifting by itself. A collection that grows and shrinks like this is called a list, and in JavaScript that is the array itself:
const cart = [];cart.push("Bread");cart.push("Milk");cart.push("Coffee");cart.push("Butter");cart.splice(cart.indexOf("Milk"), 1);console.log(cart);console.log(`Items: ${cart.length}`);[ 'Bread', 'Coffee', 'Butter' ]Items: 3pushadds at the end.- There is no method that removes by value.
indexOffinds the index of "Milk", andsplice(index, 1)removes one element from there and closes the hole: "Coffee" moves into the place of "Milk". lengthis how many elements there are right now.console.logprints the whole array in square brackets, with the text in quotes.
Here is what the array does inside. You do not choose how many places it has. The engine that runs the code does (V8 in Node and Chrome). An array of 3 items written in the code has exactly 3 places, so it fills up on the fourth:
const cart = ["Bread", "Milk", "Coffee"];cart.push("Butter");cart.splice(cart.indexOf("Milk"), 1);console.log(cart);console.log(`Items: ${cart.length}`);Step by step, in words
- cart points to an array. Inside, it has length and a separate elements array with 3 places.
- The items from the code fill the places one by one. The array is full: 3 of 3.
- There is no room. push makes an array with 22 places and copies the elements into it.
- elements now points to the new array, and nobody needs the old one. "Butter" goes into the free place.
- splice removes "Milk", and everything after it moves one place to the left. No hole is left.
- From the outside you see only an array of three items. The V8 engine decides how many places it has inside: the language does not promise it.
More precisely, if you are curious
- There is also
delete cart[1], but it does not shift anything. It leaves a hole, andlengthstays the same:
const cart = ["Bread", "Milk", "Coffee"];delete cart[1];console.log(cart, cart.length);[ 'Bread', <1 empty item>, 'Coffee' ] 3For an array, use splice.
The idea
What goes in an array
An array does not ask what you put in it. Text and a number can sit side by side:
const cart = [];cart.push("Bread");cart.push(5);console.log(cart);[ 'Bread', 5 ]That looks handy, but the error shows up later, where you expect text. So one array holds one kind of thing: only items, only prices.
JavaScript itself has no way to say "an array of text only". TypeScript does that. It is JavaScript with types: there, an array of text is string[], and cart.push(5) is an error right in the editor.
The idea
Indexes: [i], splice, indexOf, includes
An array has indexes from 0 to tasks.length - 1. You read and replace with [ ], and you insert with splice:
const tasks = ["March invoice", "Call the bank", "Warehouse report"];
console.log(tasks[0]);tasks[1] = "Meeting at the bank";tasks.splice(0, 0, "Coffee with the team");console.log(tasks.join(", "));console.log(tasks.indexOf("Warehouse report"));console.log(tasks.includes("Call the bank"));March invoiceCoffee with the team, March invoice, Meeting at the bank, Warehouse report3falsetasks[i]reads, andtasks[i] = xreplaces.splice(i, 0, x)inserts at indexiand shifts the rest to the right. The zero means "remove nothing".indexOf(x)searches and returns the index or-1, andincludes(x)only says whether it is there.join(", ")joins the elements into one piece of text, separated by commas.
More precisely, if you are curious
- An index outside the array does not stop the program. It gives
undefined.at(-1)counts from the back and gives the last element:
const tasks = ["March invoice", "Call the bank", "Warehouse report"];console.log(tasks[3]);console.log(tasks.at(-1));console.log(tasks.indexOf("Payroll"));undefinedWarehouse report-1includesandindexOfcompare with===. Text is a value, so they find text that is equal.- Inserting and removing at the front are slow in a big array: every element after the index moves by one place. For a million elements, that is a million moves.
Try it
Who is next?
The list of patients waiting at the doctor's. Ivan goes in, and Ana has an appointment, so she takes second place.
What will the program print?
const waiting = ["Ivan", "Maria", "Peter"];waiting.shift();waiting.splice(1, 0, "Ana");console.log(waiting, waiting.length);shift() removes Ivan, and Maria becomes first, at index 0. splice(1, 0, "Ana") inserts Ana at index 1 and pushes Peter to the right. Three are left.
shift() removes the first element, like splice(0, 1).
The idea
Looping over the elements
You loop over an array with for...of when you need only the elements, or with an index when you also need the number:
const cart = ["Bread", "Coffee", "Butter"];
for (const item of cart) { console.log(`- ${item}`);}for (let i = 0; i < cart.length; i++) { console.log(`${i + 1}. ${cart[i]}`);}- Bread- Coffee- Butter1. Bread2. Coffee3. ButterMore precisely, if you are curious
- Do not remove elements from an array while you loop over it with
for...of. The program does not stop, but it skips elements:
const cart = ["Bread", "Bread", "Milk"];for (const item of cart) { if (item === "Bread") { cart.splice(cart.indexOf(item), 1); }}console.log(cart);[ 'Bread', 'Milk' ]The second "Bread" stayed. splice shifted everything to the left, and the loop went on from the next index and never saw it. There is no error, so a miss like this is hard to catch.
- If you have to remove, loop with an index from the back to the front. That way, removing does not shift the elements you have not checked yet:
const cart = ["Bread", "Bread", "Milk"];for (let i = cart.length - 1; i >= 0; i--) { if (cart[i] === "Bread") { cart.splice(i, 1); }}console.log(cart);[ 'Milk' ]filter.The idea
Numbers in an array
An array of scores is like an array of text. The number sits in the array as it is:
const scores = [85, 64, 91];
let total = 0;for (const score of scores) { total += score;}console.log(`Average: ${total / scores.length}`);Average: 80JavaScript prints 80, not 80.0: whole numbers and decimals are the same type for it, number.
More precisely, if you are curious
- A number in JavaScript is a primitive value, not an object. That is why
===compares the values, and two equal numbers are equal. There is also a wrapper,new Number(257), that makes an object, and two objects are different even if they hold the same thing:
const c = Number("257");const d = Number("257");console.log(c === d);console.log(new Number(257) === new Number(257));truefalseYou do not need new Number. Write the numbers directly.
Try it
Find the bug
A theater keeps the taken seats in a array. A customer gives up seat 2, and the program should print [ 12, 7, 5 ]. Instead it prints [ 12, 2, 5 ]. Which line has the bug?
Pick the line with the bug.
splice(2, 1) removes one element from index 2, which is seat 7. To remove the value 2, first find its index: seats.splice(seats.indexOf(2), 1). Watch out if the value is not there: indexOf gives -1, and splice(-1, 1) removes the last element. So check with includes first.More precisely, if you are curious
const seats = [12, 7, 5];seats.splice(seats.indexOf(2), 1);console.log(seats);[ 12, 7 ]The idea
Sorting and an array that does not change
sort() sorts the array in place. Text comes out in alphabetical order. But numbers do not come out by size:
const cities = ["Sofia", "Plovdiv", "Varna"];cities.sort();console.log(cities);
const prices = [30, 5, 12];prices.sort();console.log(prices);prices.sort(function (a, b) { return a - b;});console.log(prices);[ 'Plovdiv', 'Sofia', 'Varna' ][ 12, 30, 5 ][ 5, 12, 30 ]With no rule, sort turns everything into text and compares the text. "12" comes before "30", and "30" before "5", as in a dictionary. So you give numbers a rule: a function that gets two numbers and returns a - b. A negative result means "a comes before b". For now, copy it. In the lesson "Classes inside classes" you will see how to write rules like this.
You make an array that does not change with Object.freeze. It is immutable: you cannot add, remove or sort in it.
const days = Object.freeze(["Mon", "Tue", "Wed"]);days.push("Thu");TypeError: Cannot add property 3, object is not extensibleconst is not enough for this: it only stops days from pointing to another array, while the array itself can still change.
More precisely, if you are curious
- Text is sorted by the codes of its characters. Capital letters come before lowercase ones, so "Pear" comes before "apple":
const fruit = ["apple", "Pear", "banana", "Grape"];fruit.sort();console.log(fruit);[ 'Grape', 'Pear', 'apple', 'banana' ]toSorted()returns a new, sorted array and does not touch the old one:
const prices = [30, 5, 12];const cheapFirst = prices.toSorted(function (a, b) { return a - b;});console.log(cheapFirst, prices);[ 5, 12, 30 ] [ 30, 5, 12 ]- How to sort your own objects, for example products by price, you will see in the lesson "Classes inside classes".
Exercise
Arrays in classes
#books), and the code below the classes only calls its methods.1. A bookshelf. A BookShelf class with a addBook(title) method that puts the book at the end, and takeBook(), which returns and removes the first book (or null if the shelf is empty). Add count() and toString(). Add "Under the Yoke", "Tobacco" and "The Iron Candlestick", take one book and print the rest.
Took: Under the Yoke2 left: [Tobacco, The Iron Candlestick]2. An event log. An Event class with a date and a description, and an EventLog class with the methods addEvent(date, description) and getEventsBetween(from, to), which returns a array of the events between the two dates, inclusive. The dates are text in the form 2026-03-31. In this form, the text sorts the same way as the dates, so <= and >= compare them correctly. Add four events: 2026-01-15 "Annual stocktake", 2026-03-31 "First quarter report", 2026-05-20 "New coffee supplier", 2026-09-01 "New school year". Print the ones from 2026-03-01 to 2026-06-30.
2026-03-31 First quarter report2026-05-20 New coffee supplier3. A notebook. A Note class with a title and content, and a Notebook class with the methods addNote, findNote(title) (returns the note or null), deleteNote(title) (returns true if it deleted something) and count(). Add the notes "OOP", "Collections" and "SQL", find "Collections", delete "OOP" and check that it is gone.
Collections: the array grows by itselfDeleted: OOPNotes: 2There is no OOP note.4. Mental math. A Question class with a text and the right answer, and a MathGame class with a array of questions, an addQuestion method and a start() method. start asks the questions one by one, reads the answer and at the end says how many were right. The questions are 2 + 2, 3 * 4 and 15 - 9.
start reads with ask from the lesson on input, so it is async start(), and the call is await game.start(). A method that waits for input is written this way. For now, copy it.
41272 + 2 = Correct!3 * 4 = Correct!15 - 9 = Wrong, the answer is 6.Score: 2 out of 3More tasks
- No repeats. Read 6 names and collect them in a array, skipping the ones that are already in it. For the input Ivan, Maria, Ivan, Ana, Maria, Peter the output is
[ 'Ivan', 'Maria', 'Ana', 'Peter' ]. - The most expensive item. A array holds prices. Find the highest one and its index, without
Math.max. - Reverse the list. Write a function that returns a new array with the same elements in reverse order. Do not change the original.
- A shopping list. Read the commands
add milk,remove milk,listandend, and keep the list between them. The command to remove an item that is not there says "No such item."
Test