Arrays come with a toolbox of methods for adding, removing, combining, and slicing elements. The single most important thing to know about each one: does it change the original array, or does it return a new one?
const queue = ["B", "C"];
queue.push("D"); // add to END ["B", "C", "D"]
queue.unshift("A"); // add to START ["A", "B", "C", "D"]
const last = queue.pop(); // remove from END returns "D"
const first = queue.shift(); // remove from START returns "A"
console.log(queue, last, first);
push / pop work on the end, like a stack of plates. shift / unshift work on the front, shifting everything else along. push and unshift return the new length; pop and shift return the removed element.
length is not just for reading. Setting it smaller chops off the end of the array:
const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.length = 2;
console.log(fruits);
at(i) returns the same as [i], but also accepts negative numbers, counting back from the end:
const letters = ["a", "b", "c"];
console.log(letters.at(0), letters[0]);
console.log(letters.at(-1), letters[-1]);
Many languages let [-1] mean "last". JavaScript cannot, because [] is also how you read object properties: letters[-1] looks for a property named "-1". at() was added in 2022 to solve this.
slice(start, end) copies from start up to, but not including, end. The original is not changed:
const letters = ["a", "b", "c", "d", "e"];
letters.slice(1, 3) // ["b", "c"]
letters.slice(2) // ["c", "d", "e"] to the end
letters.slice(-2) // ["d", "e"] last two
letters.slice() // full copy
splice(start, deleteCount, ...itemsToAdd) is the Swiss Army knife. It changes the original and returns whatever it removed:
const list = ["a", "b", "c", "d", "e"];
const removed = list.splice(1, 2); // at index 1, remove 2
console.log(list, removed); // ["a", "d", "e"] ["b", "c"]
list.splice(1, 0, "X", "Y"); // at index 1, remove 0, insert X and Y
console.log(list); // ["a", "X", "Y", "d", "e"]
list.splice(3, 1, "Z"); // at index 3, replace 1 with Z
console.log(list); // ["a", "X", "Y", "Z", "e"]
slice copies and leaves the original alone. splice cuts into the original and changes it. When in doubt, check which one you typed.
toSpliced() (added in 2023) takes the same arguments as splice, but returns a new array and leaves the original alone:
const months = ["Jan", "Feb", "Mar", "Apr"];
const spring = months.toSpliced(0, 1);
console.log(spring);
console.log(months);
Notice it returns the result, not the removed items like splice does.
const nums = [1, 2, 3];
delete nums[1];
console.log(nums, nums.length); // [1, empty, 3] 3 (leaves a hole)
const better = [1, 2, 3];
better.splice(1, 1);
console.log(better, better.length); // [1, 3] 2
delete is an operator (like typeof) that works on any object property. On arrays it removes the value and leaves a hole, so the length never changes. Use splice, pop, or shift instead.
const a = [1, 2];
const b = [3, 4];
a.concat(b) // [1, 2, 3, 4]
[...a, ...b] // [1, 2, 3, 4] (spread: the modern favorite)
[0, ...a, 2.5, ...b] // [0, 1, 2, 2.5, 3, 4] spread lets you mix in extras
concat accepts any number of arguments, and they do not have to be arrays. Single values are added as elements:
const kids = ["Emil"].concat(["Tobias", "Linus"], ["Robin"], "Peter");
console.log(kids);
const words = ["red", "green", "blue"];
words.join(", ") // "red, green, blue"
words.join(" / ") // "red / green / blue"
words.join("") // "redgreenblue"
words.toString() // "red,green,blue"
toString() is what JavaScript uses automatically whenever an array has to become text:
console.log("Colors: " + words);
[[1, 2], [3], [4, 5]].flat() // [1, 2, 3, 4, 5]
[1, [2, [3, [4]]]].flat(2) // [1, 2, 3, [4]] flatten 2 levels
With no argument, flat() flattens one level. flatMap() first transforms each element with a function, then flattens the results one level. It is handy when each item should turn into several:
console.log([1, [2, [3]]].flat());
console.log([1, 2, 3].flatMap(x => [x, x * 10]));
copyWithin(target, start, end) copies part of an array over another part of the same array. It overwrites values, never adds any, and never changes the length:
const f = ["Banana", "Orange", "Apple", "Mango", "Kiwi"];
f.copyWithin(2, 0, 2); // copy indexes 0 to 1 onto index 2
console.log(f);
You will rarely need it, but now you will recognize it.
| Changes the original | Returns something new |
|---|---|
| push, pop | slice |
| shift, unshift | concat, [...spread] |
| splice | join, toString |
| fill, copyWithin, length = n | flat, flatMap, at, toSpliced |
What does this log?
const a = [1, 2, 3, 4, 5];
a.length = 2;
console.log(a);
[1, 2]. Setting length smaller removes everything past the new length.Which method leaves the original array unchanged?
splicetoSplicedpopcopyWithintoSpliced returns a new array. The other three all change the array they are called on.What does this log?
const r = ["a", "b"].concat("c", ["d", "e"]);
console.log(r.length);
5. concat adds "c" as one element and spreads out the elements of the array ["d", "e"].["Mon", "Tue", "Wed", "Thu", "Fri"], use slice to get the middle threesplice to replace "Wed" with "HUMP DAY"join them into one sentence