JavaScript provides powerful built-in methods for adding and removing array elements. Instead of manually manipulating indices, you can use methods like push, pop, shift, unshift, splice, and slice to efficiently modify arrays. Understanding these methods is essential for effective array manipulation. Let's master these fundamental array operations!
Mutating vs Non-Mutating Methods
Before we dive in, it's important to understand the difference between methods that change the original array and those that don't.
Mutating Methods (modify original array):
- push(), pop(), shift(), unshift()
- splice()
- reverse(), sort()
Non-Mutating Methods (return new array/value):
- slice()
- concat()
- map(), filter(), reduce()
push() - Add to End
The push() method adds one or more elements to the END of an array and returns the new length.
Basic Usage
let fruits = ["apple", "banana"];
// Add one element
fruits.push("orange");
console.log(fruits); // ["apple", "banana", "orange"]
// Add multiple elements
fruits.push("grape", "mango");
console.log(fruits); // ["apple", "banana", "orange", "grape", "mango"]
// push() returns the new length
let newLength = fruits.push("kiwi");
console.log(newLength); // 6
console.log(fruits); // ["apple", "banana", "orange", "grape", "mango", "kiwi"]Common Patterns
// Building an array incrementally
let numbers = [];
for (let i = 1; i <= 5; i++) {
numbers.push(i);
}
console.log(numbers); // [1, 2, 3, 4, 5]
// Adding objects
let users = [];
users.push({ name: "Alice", age: 25 });
users.push({ name: "Bob", age: 30 });
console.log(users);
// [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }]
// Conditional adding
let evenNumbers = [];
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) {
evenNumbers.push(i);
}
}
console.log(evenNumbers); // [2, 4, 6, 8, 10]pop() - Remove from End
The pop() method removes the LAST element from an array and returns that element.
Basic Usage
let fruits = ["apple", "banana", "orange", "grape"];
// Remove last element
let removed = fruits.pop();
console.log(removed); // "grape"
console.log(fruits); // ["apple", "banana", "orange"]
// Remove again
removed = fruits.pop();
console.log(removed); // "orange"
console.log(fruits); // ["apple", "banana"]
// pop() on empty array returns undefined
let empty = [];
let result = empty.pop();
console.log(result); // undefinedUsing push() and pop() Together
// Stack behavior (Last In, First Out - LIFO)
let stack = [];
// Add items
stack.push("first");
stack.push("second");
stack.push("third");
console.log(stack); // ["first", "second", "third"]
// Remove items (in reverse order)
console.log(stack.pop()); // "third"
console.log(stack.pop()); // "second"
console.log(stack.pop()); // "first"
console.log(stack); // []
// Practical example: Undo functionality
let history = [];
function doAction(action) {
history.push(action);
console.log(`Action: ${action}`);
}
function undo() {
if (history.length > 0) {
let lastAction = history.pop();
console.log(`Undoing: ${lastAction}`);
} else {
console.log("Nothing to undo");
}
}
doAction("Type text");
doAction("Delete text");
doAction("Format text");
console.log("History:", history);
undo(); // Undoing: Format text
undo(); // Undoing: Delete text
console.log("History:", history); // ["Type text"]unshift() - Add to Beginning
The unshift() method adds one or more elements to the BEGINNING of an array and returns the new length.
let fruits = ["banana", "orange"];
// Add one element at beginning
fruits.unshift("apple");
console.log(fruits); // ["apple", "banana", "orange"]
// Add multiple elements
fruits.unshift("strawberry", "grape");
console.log(fruits); // ["strawberry", "grape", "apple", "banana", "orange"]
// unshift() returns the new length
let newLength = fruits.unshift("kiwi");
console.log(newLength); // 6
console.log(fruits);
// ["kiwi", "strawberry", "grape", "apple", "banana", "orange"]
// Practical example: Priority queue
let tasks = ["Task 3", "Task 4"];
tasks.unshift("Task 2"); // Add before existing
tasks.unshift("Task 1"); // Add urgent task first
console.log(tasks); // ["Task 1", "Task 2", "Task 3", "Task 4"]Performance Note: unshift() is slower than push() because it has to reindex all existing elements. For large arrays, consider if you really need to add to the beginning.
shift() - Remove from Beginning
The shift() method removes the FIRST element from an array and returns that element.
let fruits = ["apple", "banana", "orange", "grape"];
// Remove first element
let removed = fruits.shift();
console.log(removed); // "apple"
console.log(fruits); // ["banana", "orange", "grape"]
// Remove again
removed = fruits.shift();
console.log(removed); // "banana"
console.log(fruits); // ["orange", "grape"]
// shift() on empty array returns undefined
let empty = [];
let result = empty.shift();
console.log(result); // undefinedUsing unshift() and shift() Together
// Queue behavior (First In, First Out - FIFO)
let queue = [];
// Add items (enqueue)
queue.push("first");
queue.push("second");
queue.push("third");
console.log(queue); // ["first", "second", "third"]
// Remove items (dequeue) - in same order
console.log(queue.shift()); // "first"
console.log(queue.shift()); // "second"
console.log(queue.shift()); // "third"
console.log(queue); // []
// Practical example: Task queue
let taskQueue = [];
function addTask(task) {
taskQueue.push(task);
console.log(`Added: ${task}`);
}
function processNextTask() {
if (taskQueue.length > 0) {
let task = taskQueue.shift();
console.log(`Processing: ${task}`);
} else {
console.log("No tasks to process");
}
}
addTask("Send email");
addTask("Update database");
addTask("Generate report");
console.log("Queue:", taskQueue);
processNextTask(); // Processing: Send email
processNextTask(); // Processing: Update database
console.log("Queue:", taskQueue); // ["Generate report"]Quick Comparison
| Method | Operation | Returns | Mutates |
|---|---|---|---|
push() | Add to end | New length | ✓ Yes |
pop() | Remove from end | Removed element | ✓ Yes |
unshift() | Add to beginning | New length | ✓ Yes |
shift() | Remove from beginning | Removed element | ✓ Yes |
let arr = [1, 2, 3];
// End operations
arr.push(4); // [1, 2, 3, 4]
arr.pop(); // [1, 2, 3]
// Beginning operations
arr.unshift(0); // [0, 1, 2, 3]
arr.shift(); // [1, 2, 3]splice() - Add, Remove, or Replace
The splice() method is the Swiss Army knife of array manipulation. It can add, remove, or replace elements at any position.
Syntax
// array.splice(start, deleteCount, item1, item2, ...)
// start: index where to start changing
// deleteCount: number of elements to remove
// item1, item2, ...: elements to add
let arr = [1, 2, 3, 4, 5];Removing Elements
let fruits = ["apple", "banana", "orange", "grape", "mango"];
// Remove 2 elements starting at index 1
let removed = fruits.splice(1, 2);
console.log(removed); // ["banana", "orange"]
console.log(fruits); // ["apple", "grape", "mango"]
// Remove 1 element at index 0
let fruits2 = ["apple", "banana", "orange"];
fruits2.splice(0, 1);
console.log(fruits2); // ["banana", "orange"]
// Remove all elements from index 2 onwards
let numbers = [1, 2, 3, 4, 5];
numbers.splice(2); // No deleteCount = remove all from index
console.log(numbers); // [1, 2]Adding Elements
let fruits = ["apple", "orange"];
// Add elements at index 1 (don't remove any)
fruits.splice(1, 0, "banana", "grape");
console.log(fruits); // ["apple", "banana", "grape", "orange"]
// Add at beginning
let numbers = [3, 4, 5];
numbers.splice(0, 0, 1, 2);
console.log(numbers); // [1, 2, 3, 4, 5]
// Add at end (better to use push though)
let colors = ["red", "green"];
colors.splice(colors.length, 0, "blue");
console.log(colors); // ["red", "green", "blue"]Replacing Elements
let fruits = ["apple", "banana", "orange", "grape"];
// Replace 2 elements starting at index 1
fruits.splice(1, 2, "mango", "kiwi");
console.log(fruits); // ["apple", "mango", "kiwi", "grape"]
// Replace 1 element at index 0
let colors = ["red", "green", "blue"];
colors.splice(0, 1, "yellow");
console.log(colors); // ["yellow", "green", "blue"]
// Remove 1 and add 3
let numbers = [1, 2, 3, 4, 5];
numbers.splice(2, 1, 10, 20, 30);
console.log(numbers); // [1, 2, 10, 20, 30, 4, 5]Negative Indices
let fruits = ["apple", "banana", "orange", "grape", "mango"];
// Negative index counts from end
// -1 is last element, -2 is second to last, etc.
// Remove last element
fruits.splice(-1, 1);
console.log(fruits); // ["apple", "banana", "orange", "grape"]
// Remove second to last element
fruits.splice(-2, 1);
console.log(fruits); // ["apple", "banana", "grape"]
// Insert before last element
let colors = ["red", "green", "blue"];
colors.splice(-1, 0, "yellow");
console.log(colors); // ["red", "green", "yellow", "blue"]slice() - Extract Portion
The slice() method returns a shallow copy of a portion of an array. Unlike splice(), it does NOT modify the original array.
Basic Usage
let fruits = ["apple", "banana", "orange", "grape", "mango"];
// slice(start, end) - end is exclusive
let citrus = fruits.slice(2, 4);
console.log(citrus); // ["orange", "grape"]
console.log(fruits); // Original unchanged
// From start to end
let portion = fruits.slice(1, 3);
console.log(portion); // ["banana", "orange"]
// From start to end of array
let fromSecond = fruits.slice(2);
console.log(fromSecond); // ["orange", "grape", "mango"]
// Entire array (creates copy)
let copy = fruits.slice();
console.log(copy); // ["apple", "banana", "orange", "grape", "mango"]Negative Indices
let numbers = [1, 2, 3, 4, 5];
// Negative indices count from end
let last3 = numbers.slice(-3);
console.log(last3); // [3, 4, 5]
let secondToLast2 = numbers.slice(-3, -1);
console.log(secondToLast2); // [3, 4]
// Mix positive and negative
let middle = numbers.slice(1, -1);
console.log(middle); // [2, 3, 4]
// Copy last 2 elements
let last2 = numbers.slice(-2);
console.log(last2); // [4, 5]Common Use Cases
let items = ["a", "b", "c", "d", "e"];
// Copy array (shallow copy)
let itemsCopy = items.slice();
itemsCopy.push("f");
console.log(items); // ["a", "b", "c", "d", "e"]
console.log(itemsCopy); // ["a", "b", "c", "d", "e", "f"]
// Get first N elements
let first3 = items.slice(0, 3);
console.log(first3); // ["a", "b", "c"]
// Get last N elements
let last2 = items.slice(-2);
console.log(last2); // ["d", "e"]
// Remove first and last elements
let middle = items.slice(1, -1);
console.log(middle); // ["b", "c", "d"]splice() vs slice()
Key difference in array methods
splice() (Mutating)
// splice() - MUTATES original array
let arr1 = [1, 2, 3, 4, 5];
// Remove 2 elements at index 1
let removed = arr1.splice(1, 2);
console.log(removed); // [2, 3]
console.log(arr1); // [1, 4, 5]
// Original array changed!
// Can add/remove/replace
arr1.splice(1, 1, 10, 20);
console.log(arr1); // [1, 10, 20, 5]slice() (Non-Mutating)
// slice() - does NOT mutate
let arr2 = [1, 2, 3, 4, 5];
// Extract from index 1 to 3
let portion = arr2.slice(1, 3);
console.log(portion); // [2, 3]
console.log(arr2); // [1, 2, 3, 4, 5]
// Original array unchanged!
// Only extracts, cannot add
let copy = arr2.slice();
console.log(copy); // [1, 2, 3, 4, 5]Easy way to remember:
slice()= slice like cutting a piece of cake (original cake unchanged)splice()= splice like splicing video (original modified)
Practical Examples
Example 1: Shopping Cart Manager
class ShoppingCart {
constructor() {
this.items = [];
}
// Add item to cart
addItem(item) {
this.items.push(item);
return `Added ${item.name} to cart`;
}
// Remove last item added
removeLastItem() {
if (this.items.length > 0) {
let removed = this.items.pop();
return `Removed ${removed.name} from cart`;
}
return "Cart is empty";
}
// Remove item at specific position
removeItemAt(index) {
if (index >= 0 && index < this.items.length) {
let removed = this.items.splice(index, 1)[0];
return `Removed ${removed.name}`;
}
return "Invalid index";
}
// Get cart summary
getSummary() {
return {
itemCount: this.items.length,
items: this.items.slice() // Return copy
};
}
}
let cart = new ShoppingCart();
cart.addItem({ name: "Laptop", price: 1000 });
cart.addItem({ name: "Mouse", price: 25 });
cart.addItem({ name: "Keyboard", price: 75 });
console.log(cart.getSummary());
cart.removeItemAt(1); // Remove Mouse
console.log(cart.getSummary());Example 2: Task Queue with Priority
class TaskQueue {
constructor() {
this.tasks = [];
}
// Add normal task (to end)
addTask(task) {
this.tasks.push(task);
return `Added task: ${task}`;
}
// Add urgent task (to beginning)
addUrgentTask(task) {
this.tasks.unshift(task);
return `Added urgent task: ${task}`;
}
// Process next task (from beginning)
processNext() {
if (this.tasks.length > 0) {
let task = this.tasks.shift();
return `Processing: ${task}`;
}
return "No tasks to process";
}
// Insert task at specific position
insertTaskAt(index, task) {
this.tasks.splice(index, 0, task);
return `Inserted ${task} at position ${index}`;
}
// View all tasks
viewTasks() {
return this.tasks.slice();
}
}
let queue = new TaskQueue();
queue.addTask("Send email");
queue.addTask("Update database");
queue.addUrgentTask("Fix critical bug");
queue.insertTaskAt(1, "Review code");
console.log("Tasks:", queue.viewTasks());
console.log(queue.processNext());
console.log(queue.processNext());
console.log("Remaining:", queue.viewTasks());Example 3: Array Pagination
function paginate(array, pageSize, pageNumber) {
// Calculate start and end indices
let start = (pageNumber - 1) * pageSize;
let end = start + pageSize;
// Extract page using slice
let page = array.slice(start, end);
return {
page: page,
pageNumber: pageNumber,
pageSize: pageSize,
totalItems: array.length,
totalPages: Math.ceil(array.length / pageSize),
hasNextPage: end < array.length,
hasPreviousPage: pageNumber > 1
};
}
let items = Array.from({ length: 25 }, (_, i) => `Item ${i + 1}`);
console.log(paginate(items, 5, 1));
// Page 1: ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]
console.log(paginate(items, 5, 3));
// Page 3: ["Item 11", "Item 12", "Item 13", "Item 14", "Item 15"]
console.log(paginate(items, 5, 5));
// Page 5: ["Item 21", "Item 22", "Item 23", "Item 24", "Item 25"]Array Methods Practice
Experiment with array manipulation methods
console.log() to see your output in the console above.Key Takeaways
push()adds to end, returns new length (mutates)pop()removes from end, returns removed element (mutates)unshift()adds to beginning, returns new length (mutates)shift()removes from beginning, returns removed element (mutates)splice()adds/removes/replaces at any position (mutates)slice()extracts portion without modifying original (non-mutating)push()+pop()= Stack (LIFO)push()+shift()= Queue (FIFO)splice()is powerful but modifies original arrayslice()is safer for creating copies
What's Next?
You now understand how to add and remove array elements using powerful built-in methods! These methods are essential for array manipulation and you'll use them constantly.
In the next lesson, we'll explore Array Iteration Methods—learning forEach, map, and filter in depth. These methods enable functional programming patterns and make array processing much more elegant and efficient!
💪 Practice Challenge:
Before moving on, try creating:
- A function that removes all occurrences of a value from an array using splice
- An undo/redo system using two arrays and push/pop
- A function that rotates array elements (move first to last or vice versa)
- A pagination system using slice to display array items page by page
- A priority queue that uses unshift for urgent items and push for normal items