JavaScript • Collections and Strings

Array Methods — Use push/pop/shift/unshift and splice/slice

Master the essential methods that add, remove, and extract elements from JavaScript arrays.

JavaScript emblem with code brackets, braces, and a code file.
Inside this lesson 10 sections 5 questions 10 figures

SECTION 1

Historical Context & Motivation

Before programming languages offered built-in array methods, developers had to write low-level code to manually shift memory around whenever they wanted to add or remove an item from a list. This was tedious, error-prone, and slowed down development significantly. Early languages like C required programmers to track the size of their arrays by hand and use loops to move elements one by one.

JavaScript changed this by shipping with a set of convenient, built-in methods right on the Array object. These methods let you modify arrays with a single function call instead of writing manual loops. Understanding this evolution helps you appreciate why methods like push, pop, splice, and slice exist—they solve real problems that plagued programmers for decades.

1995 • JavaScript Is Born

Brendan Eich creates JavaScript in 10 days at Netscape. Arrays are included from the start with basic mutation capabilities.

1997 • ECMAScript 1 Standard

The first official specification formalizes array methods including push, pop, shift, unshift, splice, and slice.

2009 • ES5 Expands the Toolkit

ECMAScript 5 adds powerful iteration methods like forEach, map, and filter, all of which build on the foundation of the original mutation methods.

2015 • ES6 and Modern JavaScript

The spread operator (...) and destructuring offer new ways to work with arrays, but the classic methods remain the backbone of array manipulation.

The central question these methods answer is straightforward: how do you efficiently add, remove, or extract elements from an array without writing loops every time? Let's dive into the principles behind each method.

SECTION 2

Core Principles & Definitions

JavaScript arrays are ordered collections of values, and the six methods we are studying can be grouped by two key traits. First, does the method mutate (change) the original array, or does it return a new copy? Second, which end of the array does the method operate on—the beginning, the end, or somewhere in the middle? Keeping these two questions in mind will make every method feel intuitive.

1

Mutating vs. Non-Mutating

Methods like push, pop, shift, unshift, and splice change the original array in place. slice creates a brand-new array, leaving the original untouched.
2

End Operations: push & pop

push adds one or more elements to the end of an array and returns the new length. pop removes and returns the last element. These are the fastest operations because no other elements need to move.
3

Start Operations: unshift & shift

unshift adds elements to the beginning; shift removes the first element. Every remaining element must be re-indexed, making these slower on large arrays.
4

Middle Operations: splice

splice(start, deleteCount, ...items) is the Swiss-army knife. It can insert, remove, or replace elements at any position. It mutates the original and returns an array of the removed elements.
5

Copying a Portion: slice

slice(start, end) extracts a shallow copy from start up to (but not including) end. The original array is never modified, which makes it safe for read-only operations.
✦

KEY TAKEAWAY

Think of an array like a line of students waiting for lunch. push adds someone to the back of the line, pop pulls the last person out, unshift cuts to the front, and shift removes the person at the front. splice can yank people out of the middle or squeeze new people in anywhere. slice is like taking a photo of part of the line—nobody moves, but you get a copy of that section.

SECTION 3

Visual Explanation — push, pop, shift, unshift

The diagram below shows a five-element array and illustrates how each of the four basic methods operates on it. Pay attention to which end of the array each method targets, and notice which methods return the removed element versus the new array length.

push / pop / shift / unshift — Visual OverviewOriginal Array"A""B""C""D"[0][1][2][3]push("E")Adds to END → returns new length (5)"A""B""C""D""E"NEWpop()Removes from END → returns "D""A""B""C""D"REMOVEDunshift("Z")Adds to START → returns new length (5)"Z""A""B""C""D"NEWshift()Removes from START → returns "A""A""B""C""D"REMOVEDGreen = added · Red/Orange = removed · Dashed border = element being taken out
Each row shows the result of calling one method on the original ["A", "B", "C", "D"] array. Solid colored blocks are elements that remain; dashed outlines indicate removed elements. New additions are highlighted with bold borders.

Notice a pattern: push and pop work on the right side (end) of the array, while unshift and shift work on the left side (beginning). The methods that add elements (push and unshift) return the new length of the array, while the methods that remove elements (pop and shift) return the element that was taken out.

SECTION 4

How Each Method Works Under the Hood

Each of these six methods has a specific signature (the parameters it accepts) and a specific return value (what it gives back). Understanding these signatures is the key to using the methods confidently.

push and pop

PUSH SIGNATURE

arr.push(element1,element2,…,elementn)→newLengtharr.push(element₁, element₂, …, elementₙ) → newLength

Accepts one or more elements to add to the end. Returns the updated length of the array (a number).

POP SIGNATURE

arr.pop()→removedElementarr.pop() → removedElement

Takes no arguments. Removes and returns the last element. If the array is empty, it returns undefined.

unshift and shift

UNSHIFT SIGNATURE

arr.unshift(element1,element2,…,elementn)→newLengtharr.unshift(element₁, element₂, …, elementₙ) → newLength

Inserts elements at the beginning. All existing elements slide to higher indices. Returns the new length.

SHIFT SIGNATURE

arr.shift()→removedElementarr.shift() → removedElement

Removes the first element and shifts all remaining elements down by one index. Returns the removed element, or undefined if the array is empty.

splice and slice

SPLICE SIGNATURE

arr.splice(start,deleteCount,item1,item2,…)→[removedItems]arr.splice(start, deleteCount, item₁, item₂, …) → [removedItems]

start — index to begin changes. deleteCount — number of elements to remove. Remaining arguments are inserted at start. Returns an array of removed elements. Mutates the original array.

SLICE SIGNATURE

arr.slice(start,end)→newArrayarr.slice(start, end) → newArray

Returns a shallow copy from index start up to (but not including) end. Negative indices count backwards from the end. Does NOT mutate the original.

⚠

splice vs. slice — Don't mix them up!

A common mistake is confusing splice and slice. Remember: splice changes the array (mutates it). slice copies a portion without changing anything.

SECTION 5

splice and slice — Detailed Breakdown

While push/pop/shift/unshift each do one specific thing, splice is far more flexible. Depending on how you call it, splice can delete elements, insert elements, or do both at once. Meanwhile, slice is your go-to for extracting a subsection without disturbing the original.

splice and slice — Detailed VisualOriginal: let fruits = ["apple", "banana", "cherry", "date", "elderberry"]"apple""banana""cherry""date""elderberry"[0][1][2][3][4]splice(1, 2) — Remove 2 items starting at index 1"apple""banana""cherry""date""elderberry"Result: ["apple", "date", "elderberry"]Returns: ["banana", "cherry"]splice(2, 1, "kiwi", "mango") — Replace 1, insert 2 at index 2"apple""banana""kiwi""mango""date""elderberry"Result: ["apple", "banana", "kiwi", "mango", "date", "elderberry"]Returns: ["cherry"] (the one element that was replaced)slice(1, 4) — Copy elements from index 1 to 3 (4 not included)"apple""banana""cherry""date""elderberry"Returns NEW array: ["banana", "cherry", "date"]Original array is UNCHANGEDDashed borders = removed · Bright borders = selected by slice · Bold green = inserted by splice
This diagram demonstrates three different calls: splice(1, 2) removes two elements, splice(2, 1, "kiwi", "mango") replaces one and inserts two, and slice(1, 4) copies a sub-range without modifying the original.

The splice examples above show two common use cases. In the first, we only supplied start and deleteCount, so it purely deleted elements. In the second, we also passed replacement items after deleteCount, so it removed one element and inserted two new ones at the same position. Meanwhile, slice selected indices 1 through 3 (remember, the end index is exclusive) and returned a fresh array. The original stayed perfectly intact.

💡

Negative Indices

Both splice and slice accept negative indices. For example, slice(-2) returns the last two elements, because −2 counts backwards from the end. This is handy when you don't know the exact length of the array.

SECTION 6

Worked Example — Building a Playlist

Let's walk through a realistic scenario. Imagine you're building a music playlist app and you need to manage an array of song titles using the methods we've learned.

Managing a Song Playlist

  1. 1

    Step 1 — Create the initial playlist

    We start with three songs: let playlist = ["Bohemian Rhapsody", "Imagine", "Stairway to Heaven"];
    playlist → ["Bohemian Rhapsody", "Imagine", "Stairway to Heaven"] (length: 3)
  2. 2

    Step 2 — Add a song to the end with push

    A friend recommends "Blinding Lights", so we add it to the end: playlist.push("Blinding Lights"); The method returns 4 (the new length).
    playlist → ["Bohemian Rhapsody", "Imagine", "Stairway to Heaven", "Blinding Lights"]
  3. 3

    Step 3 — Add a priority song to the front with unshift

    You want to hear "Levitating" first, so you insert it at the beginning: playlist.unshift("Levitating"); Returns 5. Every other song shifts one index higher.
    playlist → ["Levitating", "Bohemian Rhapsody", "Imagine", "Stairway to Heaven", "Blinding Lights"]
  4. 4

    Step 4 — Remove the last song with pop

    You decide "Blinding Lights" doesn't fit the vibe, so you remove the last song: let removed = playlist.pop(); Now removed holds "Blinding Lights".
    playlist → ["Levitating", "Bohemian Rhapsody", "Imagine", "Stairway to Heaven"]
  5. 5

    Step 5 — Replace a song in the middle with splice

    You want to swap "Imagine" (index 2) with "Hotel California": playlist.splice(2, 1, "Hotel California"); This removes 1 element at index 2 and inserts the new song. The return value is ["Imagine"].
    playlist → ["Levitating", "Bohemian Rhapsody", "Hotel California", "Stairway to Heaven"]
  6. 6

    Step 6 — Copy a sub-playlist with slice

    You want to share the middle two songs without modifying your playlist: let shared = playlist.slice(1, 3); This copies indices 1 and 2 into a new array. The original playlist remains unchanged.
    shared → ["Bohemian Rhapsody", "Hotel California"] | original playlist is untouched

SECTION 7

Method Comparison — Strengths & Limitations

Now that you've seen every method in action, let's organize them side by side. The table below compares each method on four key dimensions: what it does, where it operates, whether it mutates the original, and what it returns.

MethodActionPositionMutates?Returns
push()Add element(s)EndYesNew length
pop()Remove elementEndYesRemoved element
unshift()Add element(s)BeginningYesNew length
shift()Remove elementBeginningYesRemoved element
splice()Add / Remove / ReplaceAny positionYesArray of removed items
slice()Copy a rangeAny rangeNoNew array (copy)

Comparison of the six core array methods

✦

KEY TAKEAWAY

If you need to change the original array, use the mutating methods (push, pop, shift, unshift, splice). If you need a copy without altering the source data—for instance, when displaying a filtered view while keeping the original data intact—reach for slice. Choosing the right method is like choosing the right tool from a toolbox: a hammer works great for nails, but you wouldn't use it to measure a board.

SECTION 8

Connection to Advanced Array Concepts

The six methods you've learned form the foundation for more advanced array techniques. As you progress in JavaScript, you'll encounter higher-order methods like map, filter, and reduce that accept callback functions and build on the same principles of iteration and transformation. You'll also encounter the spread operator (...) which provides a concise, non-mutating alternative to many of these operations.

Basic Method (This Lesson)Advanced AlternativeKey Difference
push(item)[...arr, item]Spread creates a new array instead of mutating
unshift(item)[item, ...arr]Non-mutating; useful in React state updates
splice() (remove)arr.filter()filter returns a new array matching a condition
slice()arr.toSpliced() (ES2023)toSpliced combines splice behavior with non-mutation

Bridging basic methods to modern JavaScript

In frameworks like React, Vue, and Angular, avoiding mutation is often preferred because it makes it easier to track changes. That's why understanding the distinction between mutating methods and non-mutating methods now will pay dividends when you start building interactive web applications. Mastering the basics covered in this lesson gives you the vocabulary and mental model to learn these advanced patterns much faster.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

Explain the difference between splice and slice. Which one mutates the original array, and which one does not?
Show answer
splice mutates (changes) the original array. It can insert, remove, or replace elements at any index, and it returns an array of the removed elements. slice does NOT mutate the original array. It returns a shallow copy of a portion of the array, from a start index up to (but not including) an end index. A helpful memory trick: splice changes, slice copies.

Question 2: BASIC CALCULATION

Given let colors = ["red", "green", "blue"];, what is the value of colors and the return value after running colors.push("yellow", "purple");?
Show answer
After colors.push("yellow", "purple"), the array becomes ["red", "green", "blue", "yellow", "purple"]. The return value of push is 5, which is the new length of the array. Remember, push can accept multiple arguments and adds all of them to the end in order.

Question 3: INTERMEDIATE

Given let nums = [10, 20, 30, 40, 50];, write the code to replace the element 30 with 35 and 37 using splice. What does the array look like after, and what does splice return?
Show answer
The element 30 is at index 2. To replace it with two new values, use nums.splice(2, 1, 35, 37);. The first argument 2 is the starting index, 1 means remove one element, and 35, 37 are the new elements to insert. After this call, nums becomes [10, 20, 35, 37, 40, 50]. The splice call returns [30]—an array containing only the removed element.

Question 4: APPLIED

You're building a to-do list app. The user has let tasks = ["Email boss", "Buy groceries", "Walk dog", "Study JS"]; They complete "Buy groceries" (index 1) and want it removed. They also want to add "Call doctor" to the very front as a high priority. Write the code using splice and unshift, and show the final array.
Show answer
First, remove the completed task: tasks.splice(1, 1); — this removes 1 element starting at index 1, returning ["Buy groceries"]. The array is now ["Email boss", "Walk dog", "Study JS"]. Next, add the urgent task to the front: tasks.unshift("Call doctor"); — this returns 4 (new length). The final array is ["Call doctor", "Email boss", "Walk dog", "Study JS"]. Note that the order of operations matters: if you used unshift first, the index of "Buy groceries" would shift to 2 instead of 1.

Question 5: CRITICAL THINKING

A classmate writes the following code expecting original to remain unchanged: let original = [1, 2, 3, 4, 5]; let copy = original; copy.splice(0, 2); However, when they log original, it shows [3, 4, 5]. Explain why this happened and how to fix it using one of the methods from this lesson.
Show answer
In JavaScript, arrays are reference types. The line let copy = original does NOT create a separate copy—it makes copy point to the exact same array in memory. So when splice mutates copy, it also changes original because they are the same array. To fix this, create a true copy first using slice: let copy = original.slice();. Calling slice() with no arguments returns a shallow copy of the entire array. Now copy.splice(0, 2) only affects copy, and original remains [1, 2, 3, 4, 5]. This pattern of using slice() to clone an array before mutating is extremely common in real-world code.

SUMMARY

Lesson Summary

Summary

JavaScript provides six essential methods for manipulating arrays. push adds elements to the end and returns the new length, while pop removes and returns the last element. unshift adds elements to the beginning and returns the new length, while shift removes and returns the first element. All four of these are mutating methods that change the original array.

For more complex operations, splice can insert, remove, or replace elements at any index and also mutates the original array. In contrast, slice is the only non-mutating method of the six—it returns a shallow copy of a portion of the array without altering the source. Remember: understanding mutation is critical because it affects how data flows through your programs and sets you up for success with advanced topics like immutable state management in modern frameworks.

Varsity Tutors • JavaScript • Array Methods — Use push/pop/shift/unshift and splice/slice