JavaScript Arrays: 15 Essential Methods Every Developer Needs in 2026
[rank_math_toc]
JavaScript arrays are the most-used data structure in the language — and most developers only scratch the surface. If you’ve been writing JavaScript with basic push() and for loops, you’re missing the tools that separate junior code from production-grade logic. This guide covers everything about JavaScript arrays: creation patterns, core methods like push, pop, splice, and slice, multidimensional arrays, sparse arrays, and the gotchas that cause real bugs.
Arrays build directly on what you’ve learned about variables and data types. Unlike primitive types, arrays are reference types — which means copying and comparing them works differently than you’d expect.
Creating JavaScript Arrays: 4 Different Ways
Most developers only know one way to create arrays. There are actually four, and each has specific use cases.
1. Array Literal (the standard way)
const fruits = ["apple", "banana", "cherry"];
const mixed = [1, "two", true, null, { key: "value" }];
const empty = [];
Array literals are the default choice 99% of the time. They’re concise, readable, and have no edge cases.
2. Array() Constructor
const arr1 = new Array(3); // Creates [empty × 3] — NOT [3]!
const arr2 = new Array(1, 2, 3); // Creates [1, 2, 3]
// The single-number trap is a classic gotcha
console.log(new Array(3).length); // 3 (three empty slots)
console.log(new Array(3)[0]); // undefined
Never use new Array(n) to create a pre-sized array. It creates a sparse array with empty slots that behave weirdly with most array methods. Use Array.from() instead.
3. Array.from() — Convert anything iterable into an array
Array.from() is one of the most powerful and underused features in JavaScript. It converts any iterable or array-like object into a real array, and optionally transforms each element.
// Create array of specific length with values
Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]
Array.from({ length: 5 }, (_, i) => i * 2); // [0, 2, 4, 6, 8]
// Convert string to array of characters
Array.from("hello"); // ["h", "e", "l", "l", "o"]
// Convert Set to array
const uniqueSet = new Set([1, 2, 2, 3, 3]);
Array.from(uniqueSet); // [1, 2, 3]
// Convert NodeList to array (from DOM queries)
const divs = document.querySelectorAll("div");
const divArray = Array.from(divs);
// Now you can use map, filter, etc.
// Generate a range
const range = (start, end) => Array.from(
{ length: end - start + 1 },
(_, i) => start + i
);
range(5, 10); // [5, 6, 7, 8, 9, 10]
4. Array.of() — No single-number trap
Array.of(3); // [3] — not three empty slots
Array.of(1, 2, 3); // [1, 2, 3]
Array.of() exists solely to fix the new Array(n) ambiguity. It always creates an array containing its arguments as elements.
Accessing and Modifying Array Elements
JavaScript arrays are zero-indexed. You access elements with bracket notation, and the .length property tells you how many elements exist.
const colors = ["red", "green", "blue"];
// Access by index
console.log(colors[0]); // "red"
console.log(colors[2]); // "blue"
// Negative indices don't work in bracket notation
console.log(colors[-1]); // undefined (NOT "blue")
// Use at() for negative indices (ES2022)
console.log(colors.at(-1)); // "blue"
console.log(colors.at(-2)); // "green"
// Modify elements
colors[1] = "yellow";
console.log(colors); // ["red", "yellow", "blue"]
// You can assign beyond the current length
colors[5] = "purple";
console.log(colors); // ["red", "yellow", "blue", empty × 2, "purple"]
console.log(colors.length); // 6
The at() Method — Clean Negative Indexing
Before at(), getting the last element of an array required arr[arr.length - 1]. The at() method was added in ES2022 and supports negative indices:
const stack = [10, 20, 30, 40, 50];
stack.at(0); // 10 (same as stack[0])
stack.at(-1); // 50 (last element)
stack.at(-2); // 40 (second to last)
Push, Pop, Shift, and Unshift in JavaScript
These four methods are your bread and butter for adding and removing elements. They mutate the original array.
const queue = ["task1", "task2"];
// push() — Add to the END. Returns new length.
queue.push("task3"); // returns 3
queue.push("task4", "task5"); // returns 5
// queue: ["task1", "task2", "task3", "task4", "task5"]
// pop() — Remove from the END. Returns removed element.
const last = queue.pop(); // "task5"
// queue: ["task1", "task2", "task3", "task4"]
// unshift() — Add to the BEGINNING. Returns new length.
queue.unshift("urgent"); // returns 5
// queue: ["urgent", "task1", "task2", "task3", "task4"]
// shift() — Remove from the BEGINNING. Returns removed element.
const first = queue.shift(); // "urgent"
// queue: ["task1", "task2", "task3", "task4"]
Performance note: push() and pop() are O(1) — constant time. shift() and unshift() are O(n) — they re-index every element. For large arrays, avoid shift/unshift in hot loops.
Splice vs Slice in JavaScript: The Crucial Difference
These two methods are constantly confused. The rule: splice mutates, slice copies.
splice() — The Swiss Army Knife (mutates)
splice(start, deleteCount, ...items) can insert, remove, and replace elements all in one call.
const arr = ["a", "b", "c", "d", "e"];
// Remove 2 elements starting at index 1
const removed = arr.splice(1, 2);
console.log(removed); // ["b", "c"]
console.log(arr); // ["a", "d", "e"]
// Insert without removing (deleteCount = 0)
arr.splice(1, 0, "x", "y");
console.log(arr); // ["a", "x", "y", "d", "e"]
// Replace: remove 1, insert 1
arr.splice(2, 1, "REPLACED");
console.log(arr); // ["a", "x", "REPLACED", "d", "e"]
slice() — Non-destructive copy
slice(start, end) returns a shallow copy of a portion of the array. The original is never modified.
const original = [10, 20, 30, 40, 50];
const middle = original.slice(1, 4); // [20, 30, 40]
const fromTwo = original.slice(2); // [30, 40, 50]
const lastTwo = original.slice(-2); // [40, 50]
const clone = original.slice(); // [10, 20, 30, 40, 50] (shallow copy)
console.log(original); // [10, 20, 30, 40, 50] — unchanged
indexOf, includes, and find — Searching JavaScript Arrays
const fruits = ["apple", "banana", "cherry", "banana"];
// indexOf — Returns first index, or -1
fruits.indexOf("banana"); // 1
fruits.indexOf("grape"); // -1
fruits.indexOf("banana", 2); // 3 (search from index 2)
// includes — Returns boolean (ES2016)
fruits.includes("cherry"); // true
fruits.includes("grape"); // false
// find — Returns first element matching a condition
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
];
const bob = users.find(u => u.id === 2);
console.log(bob); // { id: 2, name: "Bob" }
// findIndex — Returns the index instead of the element
const bobIndex = users.findIndex(u => u.id === 2); // 1
Gotcha: indexOf uses strict equality (===), so it can’t find NaN. Use includes() or find() for NaN checks. If you’re fuzzy on strict equality, review our guide on type coercion.
const arr = [1, NaN, 3];
arr.indexOf(NaN); // -1 (can't find it!)
arr.includes(NaN); // true (works correctly)
Multidimensional Arrays
JavaScript doesn’t have true multidimensional arrays — you create them by nesting arrays inside arrays.
// 2D array (matrix)
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log(matrix[1][2]); // 6 (row 1, column 2)
// Create a 3x3 grid initialized to zero
const grid = Array.from({ length: 3 }, () =>
Array.from({ length: 3 }, () => 0)
);
// [[0,0,0], [0,0,0], [0,0,0]]
// WARNING: Don't use Array(3).fill(Array(3).fill(0))
// All rows will reference the SAME inner array!
const buggy = Array(3).fill(Array(3).fill(0));
buggy[0][0] = 99;
console.log(buggy[1][0]); // 99 — all rows changed!
Sparse Arrays: The Hidden Trap
Sparse arrays have “holes” — indices with no value assigned. They’re different from indices with undefined as a value.
const sparse = [1, , 3]; // Hole at index 1
console.log(sparse.length); // 3
console.log(sparse[1]); // undefined (but the slot is empty)
// Holes behave inconsistently across methods
console.log(sparse.map(x => x * 2)); // [2, empty, 6]
console.log(sparse.filter(x => true)); // [1, 3] (holes skipped!)
console.log(sparse.forEach(x => console.log(x))); // logs 1, 3 (holes skipped)
// Compare with explicit undefined
const notSparse = [1, undefined, 3];
console.log(notSparse.filter(x => true)); // [1, undefined, 3] (included!)
The rule: never create sparse arrays intentionally. They cause subtle bugs because different methods handle holes differently. This is documented thoroughly on MDN’s sparse array guide.
Array-Like Objects: NodeList, arguments, and Strings
Several JavaScript objects look like arrays (they have indices and a length property) but aren’t actual arrays. They lack methods like map(), filter(), and push().
// arguments object (in non-arrow functions)
function oldSchool() {
console.log(arguments); // { 0: "a", 1: "b", length: 2 }
console.log(arguments.map); // undefined — not an array!
// Convert to real array
const args = Array.from(arguments);
// or: const args = [...arguments];
args.map(a => a.toUpperCase()); // works!
}
oldSchool("a", "b");
// Modern alternative: rest parameters
function modern(...args) {
// args is already a real array
args.map(a => a.toUpperCase()); // works directly
}
DOM methods like querySelectorAll() return a NodeList, and getElementsByClassName() returns an HTMLCollection. Convert them with Array.from() or the spread operator before using array methods.
Checking if Something is an Array
// The correct way
Array.isArray([1, 2, 3]); // true
Array.isArray("string"); // false
Array.isArray({ length: 3 }); // false
// DON'T use typeof — it says "object" for arrays
typeof [1, 2, 3]; // "object" — useless
// DON'T use instanceof — breaks across iframes
[] instanceof Array; // true (but unreliable cross-realm)
Performance Tips for JavaScript Arrays
- Pre-allocate when possible:
new Array(10000)then fill is faster than 10,000push()calls for very large arrays. - Avoid
delete arr[i]: This creates a sparse array. Usesplice()instead. - Typed arrays for numbers: If you’re doing heavy numeric computation, Float64Array or Int32Array are significantly faster.
- Use
Setfor membership checks:includes()is O(n).Set.has()is O(1).
Summary
JavaScript arrays are far deeper than most tutorials suggest. You now know four ways to create them, the critical difference between splice and slice, how to handle sparse arrays and array-like objects, and performance patterns for production code. Next, we’ll explore array methods like map, filter, and reduce that transform arrays into powerful data processing pipelines. You’ll also want to understand JavaScript objects since arrays and objects are frequently used together.
Further reading: MDN — Array | JavaScript.info — Arrays | V8 — Elements Kinds in V8