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.
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:
pushto add andpopto 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:
pushto join andshiftto 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 be0).- 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"is0, which is falsy, while a missing item gives-1, which is truthy. Useincludes()for yes/no, andindexOf()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
sliceandsplice.slicecopies and never changes the array.splicechanges it. - Expecting
pushto return the array. It returns the new length, soarray.push(1).push(2)fails. - Ignoring the result of
concatandslice. They do not change the original. Save the result:const all = a.concat(b);. - Forgetting that
splicechanges the array when you still need the original. - Using
if (array.indexOf(x)). Index0is falsy, and-1is truthy. Useincludes()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.
joingives"[object Object],[object Object]". Turn each object into text first. - Expecting
shiftandunshiftto be as fast aspushandpop. They move every item, so on huge arrays they are slower. - Thinking
conststops mutation.push,popandspliceall work onconstarrays.
Practice
- Start with
const nums = [1, 2, 3];. Add4at the end and0at the start. Print the array. - Remove the first and the last item of
[10, 20, 30, 40], and print the two removed values. - Given
["a", "b", "c", "d", "e"], usesliceto get["b", "c", "d"], and then usesliceto get the last two items. Check that the original did not change. - Given
["a", "b", "c", "d", "e"], usespliceto remove"c". Then usespliceto insert"X"between"b"and"d". - Replace
"banana"by"grapes"in["apple", "banana", "mango"]usingindexOfandsplice. - Merge
[1, 2],[3, 4]and[5]into one array usingconcat, and then again using spread. - Write
function isVowel(letter)that returnstrueif the letter is in["a", "e", "i", "o", "u"], usingincludes. - Turn
["2026", "10", "01"]into"2026-10-01"usingjoin. Then turn"2026-10-01"back into an array withsplit. - Explain why
console.log([1, 2, 3].push(4))prints4and not the array. - 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) andsplice(remove, insert or replace anywhere). - Non-mutating:
slice(copy a part),concat(join arrays),includes(true/false),indexOf(position or-1) andjoin(array to text). pushandunshiftreturn the new length.popandshiftreturn the removed item.splicereturns the removed items.slice(start, end)excludesend.splice(start, count, ...items)changes the array.- Use
includesfor yes/no andindexOfwhen you need the position. Never useif (indexOf(...)). push+popmake a stack.push+shiftmake a queue.- To avoid changing the original, copy first with
[...array]orslice(). - Next you will learn the most powerful array tools:
map,filterandreduce.