Array Basics
Arrays are ordered lists of values. JavaScript arrays are dynamic (no fixed size), can hold mixed types, and are zero-indexed.
// Array literal (preferred)
const fruits = ["apple", "banana", "cherry"];
const mixed = [1, "two", true, null, { id: 5 }];
const empty = [];
// Access by index (zero-based)
console.log(fruits[0]); // "apple"
console.log(fruits[2]); // "cherry"
console.log(fruits.at(-1)); // "cherry" (last element - ES2022)
console.log(fruits.at(-2)); // "banana"
// Length
console.log(fruits.length); // 3
console.log(fruits[fruits.length - 1]); // "cherry" (pre-ES2022 way)
// Check if value is an array
console.log(Array.isArray(fruits)); // true
console.log(Array.isArray("hi")); // false
// Create arrays from other things
const from1 = Array.from("hello"); // ["h","e","l","l","o"]
const from2 = Array.from({length: 3}, (_, i) => i); // [0, 1, 2]
const from3 = Array.of(7); // [7] (not [empty x 7])
Add and Remove Elements
These methods modify the original array (mutable operations):
const arr = ["a", "b", "c"];
// push / pop (end of array)
arr.push("d"); // add to end
console.log(arr); // ["a","b","c","d"]
const last = arr.pop(); // remove from end, returns removed
console.log(last); // "d"
console.log(arr); // ["a","b","c"]
// unshift / shift (start of array)
arr.unshift("z"); // add to start
console.log(arr); // ["z","a","b","c"]
const first = arr.shift(); // remove from start
console.log(first); // "z"
console.log(arr); // ["a","b","c"]
// splice(start, deleteCount, ...items)
arr.splice(1, 1); // remove 1 element at index 1
console.log(arr); // ["a","c"]
arr.splice(1, 0, "b"); // insert "b" at index 1 (delete 0)
console.log(arr); // ["a","b","c"]
arr.splice(1, 1, "X"); // replace element at index 1
console.log(arr); // ["a","X","c"]
Iterating Arrays
const nums = [10, 20, 30, 40];
// for...of - cleanest for simple iteration
for (const num of nums) {
console.log(num); // 10, 20, 30, 40
}
// forEach - for side effects, no return value
nums.forEach((num, index) => {
console.log(`${index}: ${num}`);
});
// 0: 10, 1: 20, 2: 30, 3: 40
// entries() - iterate with index
for (const [index, value] of nums.entries()) {
console.log(index, value);
}
// Classic for loop - use when you need break/continue or index
for (let i = 0; i < nums.length; i++) {
if (nums[i] === 30) break;
console.log(nums[i]); // 10, 20
}
Both iterate arrays. Prefer for...of when you need to break or continue - you cannot break out of forEach. Use forEach when you are performing side effects and want the index/value API. For transformations (producing a new value), use map/filter/reduce instead of either.
map and filter
map() transforms every element and returns a new array of the same length.
filter() keeps only elements that pass a test, returning a shorter (or equal) array.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
// map - transform each element
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10, 12, 14, 16]
const squared = numbers.map(n => n ** 2);
console.log(squared); // [1, 4, 9, 16, 25, 36, 49, 64]
// filter - keep elements that pass the test
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8]
const odds = numbers.filter(n => n % 2 !== 0);
console.log(odds); // [1, 3, 5, 7]
// Chain map and filter
const result = numbers
.filter(n => n > 3) // [4, 5, 6, 7, 8]
.map(n => n * 10); // [40, 50, 60, 70, 80]
console.log(result);
// Practical: transform an array of objects
const users = [
{ name: "Alice", age: 28, active: true },
{ name: "Bob", age: 17, active: false },
{ name: "Carol", age: 32, active: true },
];
const activeAdults = users
.filter(u => u.active && u.age >= 18)
.map(u => u.name);
console.log(activeAdults); // ["Alice", "Carol"]
reduce
reduce() iterates the array and accumulates a single result. It is the most
powerful (and most flexible) array method.
// Syntax: array.reduce((accumulator, current) => ..., initialValue)
const nums = [1, 2, 3, 4, 5];
// Sum
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15
// Product
const product = nums.reduce((acc, n) => acc * n, 1);
console.log(product); // 120
// Maximum value
const max = nums.reduce((acc, n) => (n > acc ? n : acc), -Infinity);
console.log(max); // 5
// Count occurrences
const words = ["apple", "banana", "apple", "cherry", "banana", "apple"];
const counts = words.reduce((acc, word) => {
acc[word] = (acc[word] ?? 0) + 1;
return acc;
}, {});
console.log(counts); // { apple: 3, banana: 2, cherry: 1 }
// Group by property
const people = [
{ name: "Alice", dept: "Engineering" },
{ name: "Bob", dept: "Design" },
{ name: "Carol", dept: "Engineering" },
];
const byDept = people.reduce((acc, person) => {
(acc[person.dept] ??= []).push(person.name);
return acc;
}, {});
console.log(byDept);
// { Engineering: ["Alice","Carol"], Design: ["Bob"] }
find, some, every
Methods for testing and searching arrays:
const users = [
{ id: 1, name: "Alice", age: 28 },
{ id: 2, name: "Bob", age: 17 },
{ id: 3, name: "Carol", age: 32 },
];
// find - returns first matching element (or undefined)
const bob = users.find(u => u.name === "Bob");
console.log(bob); // { id: 2, name: "Bob", age: 17 }
const notFound = users.find(u => u.age > 100);
console.log(notFound); // undefined
// findIndex - returns index of first match (or -1)
const idx = users.findIndex(u => u.id === 3);
console.log(idx); // 2
// some - true if ANY element passes the test
console.log(users.some(u => u.age < 18)); // true (Bob is 17)
console.log(users.some(u => u.age > 100)); // false
// every - true if ALL elements pass the test
console.log(users.every(u => u.age >= 18)); // false (Bob is 17)
console.log(users.every(u => u.name.length > 2)); // true
// includes - check if a primitive value is in the array
const nums = [1, 2, 3, NaN];
console.log(nums.includes(2)); // true
console.log(nums.includes(NaN)); // true (unlike indexOf, works with NaN)
console.log(nums.indexOf(NaN)); // -1 (indexOf fails with NaN)
Sorting Arrays
sort() sorts the array in-place and returns it. Always pass a comparator
function when sorting numbers.
// String sort (default - works correctly for strings)
const fruits = ["banana", "apple", "cherry", "date"];
fruits.sort();
console.log(fruits); // ["apple","banana","cherry","date"]
// Number sort - MUST use comparator
const nums = [10, 2, 100, 21, 3];
nums.sort(); // WRONG: [10, 100, 2, 21, 3] (lexicographic)
nums.sort((a, b) => a - b); // ascending
console.log(nums); // [2, 3, 10, 21, 100]
nums.sort((a, b) => b - a); // descending
console.log(nums); // [100, 21, 10, 3, 2]
// Sort objects by property
const users = [
{ name: "Carol", age: 32 },
{ name: "Alice", age: 28 },
{ name: "Bob", age: 17 },
];
users.sort((a, b) => a.age - b.age); // by age ascending
users.sort((a, b) => a.name.localeCompare(b.name)); // alphabetical
// Non-mutating sort (ES2023)
const sorted = nums.toSorted((a, b) => a - b); // returns new array
console.log(nums); // original unchanged
console.log(sorted); // sorted copy
flat, spread, and slice
// flat - flatten nested arrays
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]] (one level)
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6] (two levels)
console.log(nested.flat(Infinity)); // flatten all levels
// flatMap - map then flat(1) in one step
const sentences = ["hello world", "foo bar"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words); // ["hello","world","foo","bar"]
// Spread operator - copy or merge arrays
const a = [1, 2, 3];
const b = [4, 5, 6];
const merged = [...a, ...b]; // [1,2,3,4,5,6]
const copy = [...a]; // shallow copy
// Remove duplicates
const dup = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(dup)];
console.log(unique); // [1, 2, 3, 4]
// slice - non-mutating subarray
const nums = [10, 20, 30, 40, 50];
console.log(nums.slice(1, 3)); // [20, 30]
console.log(nums.slice(-2)); // [40, 50]
console.log(nums.slice()); // [10,20,30,40,50] (shallow copy)
Quick Reference
| Method | Mutates? | Returns | Use for |
|---|---|---|---|
push/pop | Yes | new length / removed | Add/remove at end |
unshift/shift | Yes | new length / removed | Add/remove at start |
splice | Yes | removed elements | Insert/remove anywhere |
sort | Yes | sorted array | Sort in-place |
reverse | Yes | reversed array | Reverse in-place |
map | No | new array | Transform elements |
filter | No | new array | Keep matching elements |
reduce | No | single value | Aggregate to one value |
find | No | element or undefined | First match |
some/every | No | boolean | Test conditions |
slice | No | new array | Extract subarray |
flat/flatMap | No | new array | Flatten nested arrays |
includes | No | boolean | Check if value exists |