JavaScript and TypeScript course Β· Module 5: Advanced JavaScript
Basic Array Methods
In this lesson4
A raptor herd never stands still: in the morning a new animal joins the enclosure, in the evening another one goes to the vet, and someone else has to move to the front of the feeding line. Rebuilding the array from scratch after every change would be tiring, and it is easy to lose a dinosaur along the way. JavaScript offers a range of built-in methods that let you add, remove, and modify array elements. In the context of Jurassic Park, we need them to manage lists of dinosaurs, their status, and their location.
Array-Mutating Methods
The first group of methods changes the array in place. Every piece of code that uses the same array will see the effect.
push() - Adding to the End
The push() method adds one or more elements to the end of an array and returns the new array length:
1const pack = ["Blue", "Charlie"];
2console.log(pack.length); // 2
3
4pack.push("Delta");
5console.log(pack); // ["Blue", "Charlie", "Delta"]
6
7// Adding multiple elements at once
8pack.push("Echo", "Fox");
9console.log(pack); // ["Blue", "Charlie", "Delta", "Echo", "Fox"]The herd grew even though we declared it with const - a constant guards the assignment, not the contents of the array. Remember, too, that push() returns a number, not an array, so don't treat its result as a new herd.
pop() - Removing from the End
The pop() method works the other way round: it removes the last element from an array and returns it, so you know right away who left the herd:
1const pack = ["Blue", "Charlie", "Delta", "Echo"];
2const removed = pack.pop();
3
4console.log(removed); // "Echo"
5console.log(pack); // ["Blue", "Charlie", "Delta"]Echo disappears from the array but lands in the removed variable, so the entry can go straight to the vet. On an empty array pop() does not throw an error - it simply returns undefined.
unshift() - Adding to the Beginning
The unshift() method adds elements to the beginning of an array, shifting all existing elements one position further:
1const pack = ["Charlie", "Delta"];
2pack.unshift("Blue");
3
4console.log(pack); // ["Blue", "Charlie", "Delta"]Blue now has index 0, and Charlie moves to 1. Just like push(), unshift() returns the new length of the array.
shift() - Removing from the Beginning
The shift() method removes the first element from an array and returns it. It is the natural choice when you serve the feeding queue from the front:
1const pack = ["Blue", "Charlie", "Delta"];
2const first = pack.shift();
3
4console.log(first); // "Blue"
5console.log(pack); // ["Charlie", "Delta"]The names are easy to confuse, so remember the pair: shift() takes from the beginning, unshift() adds to the beginning. Both renumber all the remaining elements.
splice() - Versatile Modification
The splice() method can add, remove, or replace elements anywhere in the array. It modifies the original array. It takes a start index, the number of elements to remove and, optionally, new elements:
1const dinosaurs = ["T-Rex", "Velociraptor", "Stegosaurus", "Triceratops"];
2
3// Remove 1 element starting at index 1
4dinosaurs.splice(1, 1);
5console.log(dinosaurs); // ["T-Rex", "Stegosaurus", "Triceratops"]
6
7// Insert an element at index 1 (without removing)
8dinosaurs.splice(1, 0, "Brachiosaurus");
9console.log(dinosaurs); // ["T-Rex", "Brachiosaurus", "Stegosaurus", "Triceratops"]
10
11// Replace the element at index 2
12dinosaurs.splice(2, 1, "Pteranodon");
13console.log(dinosaurs); // ["T-Rex", "Brachiosaurus", "Pteranodon", "Triceratops"]Every call returns an array of the removed elements - the first one would give back ["Velociraptor"]. The second shows that removing zero elements means a pure insertion, and the third combines a removal with an insertion, which is a replacement.
One Herd, Two Names
Before we move on to methods that don't mutate, meet a trap. Assigning an array to a new variable does not create a copy, just a second name for the same herd:
1const pack = ["Blue", "Charlie"];
2const nightShift = pack; // the same array, not a copy
3
4nightShift.push("Delta");
5console.log(pack); // ["Blue", "Charlie", "Delta"]
6console.log(nightShift === pack); // trueA change made through one name is visible under the other, because both variables hold a reference, a pointer to the same array in memory. This is the life cycle of data: the engine allocates memory when the array is created, your code uses it through references, and once the array is no longer reachable, the garbage collector frees it on its own. You will learn the details in the location about memory management.
Non-Mutating Methods
slice() - Copying a Portion of an Array
The slice() method returns a new array containing a portion of the original. It does not modify the original. The second argument is the index before which copying stops:
1const allDinos = ["T-Rex", "Velociraptor", "Stegosaurus", "Triceratops", "Pteranodon"];
2
3// slice(start, end) - from index start up to (but not including) end
4const herbivores = allDinos.slice(2, 4);
5console.log(herbivores); // ["Stegosaurus", "Triceratops"]
6console.log(allDinos); // Original unchanged!
7
8// Copy the entire array
9const copy = allDinos.slice();
10console.log(copy); // ["T-Rex", "Velociraptor", "Stegosaurus", "Triceratops", "Pteranodon"]The element at the end index is not included, which is why slice(2, 4) returns two dinosaurs. Calling it without arguments copies the whole array - the cure for the reference trap. The copy is shallow, though: the objects inside stay shared.
Key Difference: splice() vs slice()
| Feature | splice() | slice() |
|---|---|---|
| Mutation | YES - modifies the original array | NO - returns a new array |
| Parameters | (start, deleteCount, ...items) | (start, end) |
| Use case | Adding/removing/replacing elements | Extracting a portion of an array |
The names differ by one letter and the behavior by everything: splice() rearranges the herd, slice() takes a photo of part of it. When you don't need to change the original, I recommend slice() - code without unexpected mutations is easier to follow.
Method Chains: map, filter and forEach
Non-mutating methods have one more advantage: since they return a new array, you can call the next method on the result right away. That is how a chain is formed. Three methods show up in chains most often - map() transforms every element, filter() keeps only the matching ones, and forEach() performs an action for each:
1const pack = ["Blue", "Charlie", "Delta", "Echo"];
2
3const tags = pack.map(name => name.toUpperCase());
4console.log(tags); // ["BLUE", "CHARLIE", "DELTA", "ECHO"]
5
6const longNames = pack.filter(name => name.length > 4);
7console.log(longNames); // ["Charlie", "Delta"]
8
9// A chain: filter first, then transform
10const alarms = pack.filter(name => name.length > 4).map(name => name + "!");
11console.log(alarms); // ["Charlie!", "Delta!"]
12
13pack.forEach(name => console.log("Present:", name)); // returns undefined
14console.log(pack); // ["Blue", "Charlie", "Delta", "Echo"] - unchangedmap() always returns a new array of the same length, and filter() a shorter or equal one. forEach() returns only undefined, so the chain cannot continue after it. The last line confirms that the original herd was left untouched. A fourth method, reduce(), folds an array into a single value - we will deal with it in the next lesson.
In the lab below you will practice adding and removing raptors, and then splice() and slice().
Remember: mutating methods rearrange the herd in the enclosure, while non-mutating ones take its photo without moving a single raptor.
Code for this lesson: index.js
1// Basic array methods - Managing a raptor pack
2
3const pack = ["Blue", "Charlie"];
4console.log("Starting pack:", pack);
5
6// push() - add to the end
7pack.push("Delta");
8console.log("After push('Delta'):", pack);
9
10// pop() - remove from the end
11const removed = pack.pop();
12console.log("After pop():", pack, "| Removed:", removed);
13
14// unshift() - add to the beginning
15pack.unshift("Alpha");
16console.log("After unshift('Alpha'):", pack);
17
18// shift() - remove from the beginning
19const first = pack.shift();
20console.log("After shift():", pack, "| Removed:", first);
21
22// === EXERCISE ===
23// TODO: Create an array dinosaurs with 5 dinosaurs
24const dinosaurs = ["T-Rex", "Velociraptor", "Stegosaurus", "Triceratops", "Pteranodon"];
25
26// TODO: Use splice() to remove 1 element starting at index 2
27// TODO: Use splice() to insert "Brachiosaurus" at index 1
28
29console.log("\n=== splice() ===");
30console.log("After the splice operations:", dinosaurs);
31
32// TODO: Use slice() to cut out the elements from index 1 to 3
33// Remember: slice() does NOT modify the original array!
34const fragment = dinosaurs.slice(1, 3);
35console.log("\n=== slice() ===");
36console.log("Fragment:", fragment);
37console.log("Original unchanged:", dinosaurs);Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What does the push() method do in a JavaScript array?
2. What is the difference between shift() and unshift() in arrays?
These are 2 of 4 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Code editor
Create a pack array and add/remove Velociraptors using push, pop, shift, unshift.
- Vertical ordering
Arrange the syntax for creating an object with a nested array: