Q1With const items = ["Pen", "Tape", "Memo"];, what are the values of length and the last element's index?
Arrays — Adding, Removing, and Retrieving
Learn arrays, from reading elements by index to adding and removing at both ends, checking membership, and slicing.
Keep cart items in separate variables — item1 / item2 / item3 — and every new product means adding another variable and rewriting the code that counts them. An array (a data structure that holds multiple values in order in one variable) lets you hold any number of items in a single variable, and leaves adding and removing to the array's own methods.
Lining Up Values in an Array — index and length
You build an array by listing values, separated by commas, inside [ and ]. Each individual value is called an element (one of the values stored in an array). You can mix strings and numbers, but in practice you keep an array to a single kind of value, so the code that works on it later stays consistent.
You pull out a stored element by writing its index (an element's position, counted from 0) inside []. Write cart[1] = "Tape", and only the element at that position gets replaced.
cart[0] is the 1st item, cart[1] is the 2nd. Since the first item's index is 0, indexes run one behind the way people normally count.
length is the number of elements. Write it without parentheses, as in cart.length. Since index starts at 0, the last element's index is length minus 1.
at(-1) counts from the end, letting you grab the last element without going through length. at(-2) is the 2nd from the end.
Reading an out-of-range index doesn't throw an error — you get back undefined, the value that means nothing has been assigned yet.
cart.length is 3 and the last index is 2. Counting from the end with at(-1) returns the same element.const cart = ["Notebook", "Pen", "Tape"];
console.log(cart[0]); // Notebook
console.log(cart[2]); // Tape
console.log(cart.length); // 3
// The last item is at length minus 1, or use at(-1)
console.log(cart[cart.length - 1]); // Tape
console.log(cart.at(-1)); // Tape
// Reading an out-of-range index doesn't error
console.log(cart[5]); // undefined
Adding and Removing at Both Ends — push / pop / shift / unshift
A cart's contents change every time an item is added or removed. If you rewrote the array by hand every time, you'd be managing the count and every index yourself. Arrays have methods for adding and removing elements at both ends, so you can leave the position math to them.
push(value) adds an element at the end and returns the array's new length. pop() removes the last element and returns that removed element itself.
To print the name of whatever got removed, store the method's result (its return value) in a variable, as in const removed = cart.pop();.
unshift(value) and shift() handle the front. unshift adds to the front, and shift removes from the front. Add one item at the front, and every element after it moves up one index.
const cart = ["Pen"];
console.log(cart.push("Tape")); // 2 (the new length)
console.log(cart.join(", ")); // Pen, Tape
console.log(cart.pop()); // Tape (the removed element)
console.log(cart.join(", ")); // Pen
cart.unshift("Memo"); // add to the front
console.log(cart.join(", ")); // Memo, Pen
console.log(cart.shift()); // Memo (the removed element)
console.log(cart.join(", ")); // Pen
It might seem odd that the contents of cart can change when it's declared with const. What const forbids is reassigning the name to a different value, as in cart = someOtherArray; it doesn't stop you from rewriting the array's contents, as with cart.push(value). Why this distinction exists is covered in a later article.
Checking Whether Something's Included — includes and indexOf
Try to add the same product to a favorites list a second time with a plain push, and you'll get the same name listed twice. Checking whether a value is already in the array before adding it prevents duplicates.
includes(value) returns true if that value is in the array, false if not. When you need the position too, use indexOf(value), which returns the index of the first match. It returns -1 when nothing matches.
The idea is the same as a string's includes / indexOf — you're just searching for an element instead of a character.
Both compare types as well as values, exactly the way === does, so values of different types never match. Pass the string "2" to an array of numbers, and it won't count as a match.
["Memo", "Board"]. Use includes when you just need yes/no, indexOf when you need the position too. indexOf returns -1 when nothing matches.const favorites = ["Memo", "Board"];
console.log(favorites.includes("Memo")); // true
console.log(favorites.includes("Eraser")); // false
console.log(favorites.indexOf("Board")); // 1
console.log(favorites.indexOf("Eraser")); // -1
// Compares like ===, so different types never match
const quantities = [1, 2, 3];
console.log(quantities.includes("2")); // false
Don't Drop indexOf's Result Straight Into a Condition
When the match is the very first element, indexOf returns 0. Since 0 is falsy, writing if (favorites.indexOf(name)) treats only that front element as "not there." Use includes when all you want is yes/no, and when you do use indexOf, compare its result explicitly, as in !== -1.
Extracting or Replacing Part of an Array — slice and splice
Maybe you want to show only the top 3 in a sales ranking, or swap out just one entry in a list of shipping options. The difference comes down to whether you're pulling values out and leaving the original array alone, or rewriting the original array itself.
slice(start, end) returns a new array containing everything from the start index up to, but not including, the end index. The original array doesn't change.
Leave off the end, and it extracts through the end of the array. It counts the same way a string's slice does.
splice(start, deleteCount, itemsToAdd) rewrites the original array itself. It removes deleteCount elements starting at start, and if you pass items to add, it inserts them right at that position.
It returns an array of the removed elements, so when you remove just one, read its contents with [0].
| Syntax | Returns | Original Array |
|---|---|---|
| slice(start, end) | A new array with the extracted items | Unchanged |
| splice(start, deleteCount) | An array of the removed elements | Rewritten |
| splice(start, deleteCount, itemsToAdd) | An array of the removed elements | Rewritten |
const ranking = ["Pen", "Tape", "Memo", "Board"];
// slice returns a new array; ranking is unchanged
const top2 = ranking.slice(0, 2);
console.log(top2.join(", ")); // Pen, Tape
console.log(ranking.length); // 4
// splice rewrites ranking itself
const removed = ranking.splice(1, 2, "Eraser");
console.log(removed.join(", ")); // Tape, Memo
console.log(ranking.join(", ")); // Pen, Eraser, Board
console.log(ranking.length); // 3
slice and splice Are One Letter Apart, But the Results Differ
The names look alike, but slice leaves the original array alone and returns a new one, while splice rewrites the original. Call splice just to display a list, and the underlying data shrinks a little every time you display it. If you only need to pull values out, reach for slice.
Knowledge Check
Answer each question one by one.
Q2What does cart.pop() return?
Q3Which of these leaves the original array unchanged when called?