JavaScriptBeginner

JavaScript Array Methods: push, pop, slice, splice and More

Learn the essential array methods push, pop, shift, unshift, slice, splice, concat, includes, indexOf and join, and which ones change your original array.

All JavaScript lessons

What you will learn

An array is only useful if you can add, remove, copy, search and combine its items. JavaScript gives every array a toolbox of built-in functions, called methods, for exactly that. In this lesson you will master ten of the most important ones: push, pop, shift, unshift, slice, splice, concat, includes, indexOf and join. Most importantly, you will learn which ones change your original array and which ones do not.

What is a method?

A method is a function that belongs to a value. You call it with a dot, then the method name, then brackets:

const fruits = ["apple", "banana"];

fruits.push("mango");   // array.method(arguments)

The big idea: mutating vs non-mutating

Before the methods, one idea that will save you hours of debugging.

  • A mutating method changes the original array.
  • A non-mutating method leaves the original alone and returns a new value.
Method What it does Changes the original? Returns
push(...) Adds to the end Yes New length
pop() Removes from the end Yes The removed item
unshift(...) Adds to the start Yes New length
shift() Removes from the start Yes The removed item
splice(...) Removes / inserts / replaces anywhere Yes Array of removed items
slice(...) Copies a part No New array
concat(...) Joins arrays No New array
includes(x) Is x in the array? No true / false
indexOf(x) Where is x? No Index, or -1
join(sep) Turns the array into text No A string

Keep this table handy. Now let us go through each method.

Adding and removing at the ends

Picture a row of numbered boxes. You can work at the right end (the end of the array) or the left end (the start).

 start                       end
   ↓                          ↓
 unshift / shift      push / pop

push(): add to the end

const fruits = ["apple", "banana"];

fruits.push("mango");
console.log(fruits);   // ["apple", "banana", "mango"]

fruits.push("kiwi", "grapes");   // add several at once
console.log(fruits);   // ["apple", "banana", "mango", "kiwi", "grapes"]

push returns the new length, not the array:

const list = [1, 2];
const newLength = list.push(3);
console.log(newLength);   // 3

pop(): remove from the end

const fruits = ["apple", "banana", "mango"];

const removed = fruits.pop();

console.log(removed);   // "mango"
console.log(fruits);    // ["apple", "banana"]

pop returns the item it removed. On an empty array it returns undefined.

unshift(): add to the start

const fruits = ["banana", "mango"];

fruits.unshift("apple");
console.log(fruits);   // ["apple", "banana", "mango"]

shift(): remove from the start

const fruits = ["apple", "banana", "mango"];

const first = fruits.shift();

console.log(first);    // "apple"
console.log(fruits);   // ["banana", "mango"]

Stack and queue

Two famous patterns come from these four methods:

  • Stack (last in, first out), like a pile of plates: push to add and pop to remove. The last item added is the first one taken out. (Think of the undo button.)
  • Queue (first in, first out), like a line at a ticket counter: push to join and shift to serve. The first person in line is the first to leave.
// Stack (undo history)
const history = [];
history.push("typed A");
history.push("typed B");
console.log(history.pop());   // "typed B"  (undo the last action)

// Queue (customers)
const line = [];
line.push("Riya");
line.push("Karan");
console.log(line.shift());    // "Riya"  (first come, first served)

slice(): copy a part

slice(start, end) returns a new array with the items from start up to, but not including, end. The original is untouched.

const letters = ["a", "b", "c", "d", "e"];

console.log(letters.slice(1, 3));    // ["b", "c"]   (index 1 and 2)
console.log(letters.slice(2));       // ["c", "d", "e"]  (from index 2 to the end)
console.log(letters.slice(-2));      // ["d", "e"]   (last two items)
console.log(letters.slice(1, -1));   // ["b", "c", "d"]  (without first and last)
console.log(letters);                // ["a", "b", "c", "d", "e"]  (unchanged)

Calling slice() with no arguments makes a copy of the whole array:

const letters = ["a", "b", "c"];
const copy = letters.slice();   // same as [...letters]
console.log(copy);              // ["a", "b", "c"]

Like with strings, think of the numbers as markers between the items. slice(1, 3) cuts between marker 1 and marker 3.

splice(): remove, insert or replace

splice is the Swiss Army knife. It changes the original array. Its shape:

array.splice(startIndex, deleteCount, item1, item2, ...)
  • startIndex: where to begin.
  • deleteCount: how many items to remove (can be 0).
  • items: what to insert at that position (optional).

It returns an array of the removed items.

Remove items

const fruits = ["apple", "banana", "mango", "kiwi"];

const removed = fruits.splice(1, 2);   // from index 1, remove 2 items

console.log(removed);   // ["banana", "mango"]
console.log(fruits);    // ["apple", "kiwi"]

Insert items (delete nothing)

const fruits = ["apple", "kiwi"];

fruits.splice(1, 0, "banana", "mango");   // at index 1, remove 0, insert 2

console.log(fruits);   // ["apple", "banana", "mango", "kiwi"]

Replace an item

const fruits = ["apple", "banana", "kiwi"];

fruits.splice(1, 1, "grapes");   // remove 1 item at index 1, put "grapes" there

console.log(fruits);   // ["apple", "grapes", "kiwi"]

Remove everything from a position to the end

If you leave out deleteCount, it removes all the items from startIndex onwards:

const numbers = [1, 2, 3, 4, 5];

numbers.splice(2);
console.log(numbers);   // [1, 2]

Slice vs splice: do not mix them up

slice splice
Changes the original? No Yes
Returns A copy of a part The removed items
Second argument means End index (excluded) How many to remove

Memory trick: a slice of cake is a copy of a piece, and the cake can still be whole. Splice is like splicing a film or a rope: you cut it and join it back, and the original changes.

concat(): join arrays

concat returns a new array with the items of all the arrays (or values) you give it. The originals stay the same.

const fruits = ["apple", "banana"];
const veggies = ["carrot", "potato"];

const food = fruits.concat(veggies);
console.log(food);      // ["apple", "banana", "carrot", "potato"]
console.log(fruits);    // ["apple", "banana"]  (unchanged)

console.log(fruits.concat("mango", ["kiwi", "grapes"]));
// ["apple", "banana", "mango", "kiwi", "grapes"]

The spread syntax does the same job, and many developers prefer it:

const fruits = ["apple", "banana"];
const veggies = ["carrot", "potato"];

const food2 = [...fruits, ...veggies];
const withExtra = [...fruits, "mango", ...veggies];

console.log(food2);       // ["apple", "banana", "carrot", "potato"]
console.log(withExtra);   // ["apple", "banana", "mango", "carrot", "potato"]

Remember: concat does not change fruits. If you ignore its result, nothing happens:

const fruits = ["apple", "banana"];
const veggies = ["carrot", "potato"];

fruits.concat(veggies);          // result thrown away!
console.log(fruits.length);      // still 2

includes(): is it in the array?

includes answers true or false:

const fruits = ["apple", "banana", "mango"];

console.log(fruits.includes("banana"));   // true
console.log(fruits.includes("grapes"));   // false
console.log(fruits.includes("Banana"));   // false (case matters!)

It compares with strict equality (===), so "5" and 5 are different:

console.log([1, 2, 3].includes("2"));   // false

includes also finds NaN, which indexOf cannot:

console.log([NaN].includes(NaN));   // true
console.log([NaN].indexOf(NaN));    // -1

It shines for replacing long conditions:

const role = "editor";

// Instead of:  role === "admin" || role === "editor" || role === "moderator"
if (["admin", "editor", "moderator"].includes(role)) {
  console.log("You can edit posts");
}

A catch with objects

const users = [{ name: "Riya" }];

console.log(users.includes({ name: "Riya" }));   // false

Two separate objects are never ===, even if they look the same. For objects, you need other tools (some and find, coming in a later lesson).

indexOf(): where is it?

indexOf returns the position of the first match, or -1 if the item is not there.

const fruits = ["apple", "banana", "mango", "banana"];

console.log(fruits.indexOf("banana"));   // 1  (first match)
console.log(fruits.indexOf("grapes"));   // -1 (not found)
console.log(fruits.lastIndexOf("banana"));   // 3 (search from the end)

Use -1 to test “not found”:

const fruits = ["apple", "banana", "mango"];

if (fruits.indexOf("grapes") === -1) {
  console.log("Not in the list");
}

Bug alert: if (fruits.indexOf("apple")) is wrong. The index of "apple" is 0, which is falsy, while a missing item gives -1, which is truthy. Use includes() for yes/no, and indexOf() only when you need the position.

join(): array to text

join glues the items into one string, with a separator of your choice (comma by default):

const words = ["JavaScript", "is", "fun"];

console.log(words.join());          // "JavaScript,is,fun"
console.log(words.join(" "));       // "JavaScript is fun"
console.log(words.join("-"));       // "JavaScript-is-fun"
console.log(words.join(""));        // "JavaScriptisfun"
console.log(words.join(" | "));     // "JavaScript | is | fun"

null and undefined items become empty text:

console.log([1, null, 3].join("-"));   // "1--3"

join is the opposite of the string method split:

const text = "red,green,blue";
const colors = text.split(",");       // ["red", "green", "blue"]
const again = colors.join(",");       // "red,green,blue"

Together, they let you transform text step by step:

const title = "  learn java script fast  ";

const slug = title.trim().split(" ").join("-");
console.log(slug);   // "learn-java-script-fast"

const reversed = "hello".split("").reverse().join("");
console.log(reversed);   // "olleh"

(reverse() flips an array in place. It works here because the temporary array from split is thrown away anyway.)

Real-life use cases

1. To-do list: add and remove tasks

const todos = ["Buy milk", "Study JavaScript"];

// Add
todos.push("Go for a walk");

// Remove a task by name
const index = todos.indexOf("Buy milk");
if (index !== -1) {
  todos.splice(index, 1);
}

console.log(todos);   // ["Study JavaScript", "Go for a walk"]

2. Shopping cart: add only if it is not there

const cart = ["shirt", "shoes"];

function addToCart(item) {
  if (cart.includes(item)) {
    console.log(item + " is already in your cart");
  } else {
    cart.push(item);
    console.log(item + " added");
  }
}

addToCart("hat");     // "hat added"
addToCart("shirt");   // "shirt is already in your cart"
console.log(cart);    // ["shirt", "shoes", "hat"]

3. Toggle a selection (add if missing, remove if present)

const selected = ["red"];

function toggleColor(color) {
  const index = selected.indexOf(color);

  if (index === -1) {
    selected.push(color);
  } else {
    selected.splice(index, 1);
  }
}

toggleColor("blue");
toggleColor("red");
console.log(selected);   // ["blue"]

This is exactly how “select multiple filters” works on shopping sites.

4. Undo history (a stack)

const history = [];

function doAction(action) {
  history.push(action);
}

function undo() {
  return history.pop();
}

doAction("bold");
doAction("underline");
doAction("italic");

console.log(undo());      // "italic"
console.log(history);     // ["bold", "underline"]

5. Ticket counter (a queue)

const queue = ["Riya", "Karan", "Neha"];

console.log("Now serving:", queue.shift());   // "Riya"
queue.push("Aman");

console.log(queue);   // ["Karan", "Neha", "Aman"]

6. Pagination with slice

const items = ["a", "b", "c", "d", "e", "f", "g"];
const pageSize = 3;

function getPage(pageNumber) {
  const start = (pageNumber - 1) * pageSize;
  return items.slice(start, start + pageSize);
}

console.log(getPage(1));   // ["a", "b", "c"]
console.log(getPage(2));   // ["d", "e", "f"]
console.log(getPage(3));   // ["g"]

7. Top 3 scores

const scores = [72, 95, 60, 88, 79, 91];

const top3 = [...scores].sort((a, b) => b - a).slice(0, 3);

console.log(top3);     // [95, 91, 88]
console.log(scores);   // [72, 95, 60, 88, 79, 91]  (untouched, because we copied first)

We copy with [...scores] before sort, because sort changes the array it is called on.

8. Insert a song into a playlist

const playlist = ["Song A", "Song B", "Song D"];

playlist.splice(2, 0, "Song C");   // insert at index 2, remove nothing

console.log(playlist);   // ["Song A", "Song B", "Song C", "Song D"]

9. Merge two lists without duplicates

const mine = ["js", "html"];
const yours = ["css", "js"];

const all = [...new Set(mine.concat(yours))];
console.log(all);   // ["js", "html", "css"]

10. Breadcrumbs and CSV text

const path = ["Home", "Courses", "JavaScript"];

console.log(path.join(" > "));   // "Home > Courses > JavaScript"

const row = ["Riya", 20, "Delhi"];
console.log(row.join(","));      // "Riya,20,Delhi"

Newer non-mutating versions

Because mutating methods surprise people, modern JavaScript added safer twins that return a new array: toSorted(), toReversed() and toSpliced(). They work like their older relatives but leave the original alone. They are available in all current browsers. If you need to support very old browsers, copy first with [...array] as shown above.

Common mistakes

  • Mixing up slice and splice. slice copies and never changes the array. splice changes it.
  • Expecting push to return the array. It returns the new length, so array.push(1).push(2) fails.
  • Ignoring the result of concat and slice. They do not change the original. Save the result: const all = a.concat(b);.
  • Forgetting that splice changes the array when you still need the original.
  • Using if (array.indexOf(x)). Index 0 is falsy, and -1 is truthy. Use includes() or compare with -1.
  • Using includes() with objects. It checks identity, not content.
  • Using splice(index) without a count. It removes everything from that index to the end.
  • Calling splice(-1, 1) without thinking. A negative index counts from the end, so it removes the last item. That is fine only if you mean it.
  • Removing items while looping forward. Items shift and some get skipped. Loop backwards, or build a new array instead.
  • Joining an array of objects. join gives "[object Object],[object Object]". Turn each object into text first.
  • Expecting shift and unshift to be as fast as push and pop. They move every item, so on huge arrays they are slower.
  • Thinking const stops mutation. push, pop and splice all work on const arrays.

Practice

  1. Start with const nums = [1, 2, 3];. Add 4 at the end and 0 at the start. Print the array.
  2. Remove the first and the last item of [10, 20, 30, 40], and print the two removed values.
  3. Given ["a", "b", "c", "d", "e"], use slice to get ["b", "c", "d"], and then use slice to get the last two items. Check that the original did not change.
  4. Given ["a", "b", "c", "d", "e"], use splice to remove "c". Then use splice to insert "X" between "b" and "d".
  5. Replace "banana" by "grapes" in ["apple", "banana", "mango"] using indexOf and splice.
  6. Merge [1, 2], [3, 4] and [5] into one array using concat, and then again using spread.
  7. Write function isVowel(letter) that returns true if the letter is in ["a", "e", "i", "o", "u"], using includes.
  8. Turn ["2026", "10", "01"] into "2026-10-01" using join. Then turn "2026-10-01" back into an array with split.
  9. Explain why console.log([1, 2, 3].push(4)) prints 4 and not the array.
  10. Challenge: write a toggleItem(list, item) function that adds the item if it is missing and removes it if it is present, without changing the original array (return a new array).

Recap

  • Methods are built-in functions of arrays. Know which ones change the original (mutating) and which return something new.
  • Mutating: push (add at end), pop (remove from end), unshift (add at start), shift (remove from start) and splice (remove, insert or replace anywhere).
  • Non-mutating: slice (copy a part), concat (join arrays), includes (true/false), indexOf (position or -1) and join (array to text).
  • push and unshift return the new length. pop and shift return the removed item. splice returns the removed items.
  • slice(start, end) excludes end. splice(start, count, ...items) changes the array.
  • Use includes for yes/no and indexOf when you need the position. Never use if (indexOf(...)).
  • push + pop make a stack. push + shift make a queue.
  • To avoid changing the original, copy first with [...array] or slice().
  • Next you will learn the most powerful array tools: map, filter and reduce.