JavaScript Arrays — The Complete Course
Prerequisites
Basic JavaScript: variables, functions, if, and loops.
Level 1 — Basics
Array Literals
Arrays store ordered collections. Created with square brackets:
const fruits = ['apple', 'banana', 'cherry'];
const mixed = [1, 'hello', true, null, { id: 5 }];
const empty = [];
Element Access
Zero-indexed. First element at [0], last at [length - 1].
const colors = ['red', 'green', 'blue'];
colors[0]; // 'red'
colors[1]; // 'green'
colors[2]; // 'blue'
colors[99]; // undefined (no error)
Element Assignment
const arr = ['a', 'b', 'c'];
arr[1] = 'x';
// arr: ['a', 'x', 'c']
You can assign to any index. If the index is beyond length, the array grows and empty slots fill the gap:
const arr = ['a'];
arr[3] = 'b';
// arr: ['a', empty × 2, 'b']
// arr.length: 4
The length Property
length is not the count of elements — it’s the highest index + 1.
const arr = ['a', 'b', 'c'];
arr.length; // 3
// Truncate
arr.length = 1;
// arr: ['a']
// Extend (creates empty slots)
arr.length = 5;
// arr: ['a', empty × 4]
Checking for Arrays
Array.isArray([1, 2, 3]); // true
Array.isArray('hello'); // false
Array.isArray({ length: 3 }); // false (array-like ≠ array)
Quiz: Element Assignment
What does arr look like after this code?
const arr = [10, 20];
arr[5] = 50;
Answer
arr is [10, 20, empty × 3, 50] with length === 6.
Quiz: Element Access
What does this return?
[1, 2, 3][10]
Answer
undefined. Accessing a non-existent index never throws — it returns undefined.
Quiz: Empty Array
What is the length of []? What is [][0]?
Answer
length is 0. [][0] is undefined.
Level 2 — Stack, Iteration & Map
Stack Operations: push and pop
Arrays work as stacks. push appends, pop removes from the end.
const stack = [];
stack.push('a'); // ['a']
stack.push('b', 'c'); // ['a', 'b', 'c'] — push returns new length: 3
stack.pop(); // returns 'c', stack: ['a', 'b']
stack.pop(); // returns 'b', stack: ['a']
stack.pop(); // returns 'a', stack: []
stack.pop(); // returns undefined, stack: [] (no error on empty)
Key detail: push returns the new length. pop returns the removed element (or undefined if empty).
Queue Operations: shift and unshift
const q = ['b', 'c'];
q.unshift('a'); // ['a', 'b', 'c'] — returns new length: 3
q.shift(); // returns 'a', q: ['b', 'c']
q.shift(); // returns 'b', q: ['c']
q.shift(); // returns 'c', q: []
q.shift(); // returns undefined, q: [] (empty)
shift/unshift are O(n) — they re-index all remaining elements. Prefer push/pop for performance.
forEach — Side Effects
Executes a callback for each element. Returns undefined. Use for side effects (logging, mutating external state), not for building new arrays.
const fruits = ['apple', 'banana', 'cherry'];
fruits.forEach((fruit, index, array) => {
console.log(`${index}: ${fruit}`);
});
// 0: apple
// 1: banana
// 2: cherry
Callback signature: (element, index, array). index and array are optional.
Key behavior: forEach skips empty slots in sparse arrays:
const sparse = ['a', , 'c'];
sparse.forEach((v, i) => console.log(i, v));
// 0 'a'
// 2 'c'
// Index 1 is skipped entirely
Cannot break out of a forEach early. Use for...of, some, every, or find instead.
map — Transformation
Creates a new array where each element is the return value of the callback. Never mutates the original.
const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2);
// doubled: [2, 4, 6]
// nums unchanged: [1, 2, 3]
Map with index:
const indexed = ['a', 'b', 'c'].map((item, i) => ({ index: i, value: item }));
// [{ index: 0, value: 'a' }, { index: 1, value: 'b' }, { index: 2, value: 'c' }]
Extract a field (pluck):
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
const names = users.map(u => u.name);
// ['Alice', 'Bob']
Map skips empty slots (like forEach):
[, 2, , 4].map(x => x * 2);
// [empty, 4, empty, 8]
Quiz: Add Exclamation
const words = ['hello', 'world'];
// Use map to produce: ['hello!', 'world!']
Answer
words.map(w => w + '!');
Quiz: Square
const nums = [1, 2, 3, 4, 5];
// Use map to produce: [1, 4, 9, 16, 25]
Answer
nums.map(n => n * n);
flat and flatMap
flat(depth) — flattens nested arrays to the specified depth (default 1):
const nested = [1, [2, [3, [4]]]];
nested.flat(); // [1, 2, [3, [4]]]
nested.flat(2); // [1, 2, 3, [4]]
nested.flat(Infinity); // [1, 2, 3, 4] — completely flatten
flatMap(callback) — map then flat(1) in one pass. More efficient than separate calls.
const sentences = ['Hello world', 'foo bar'];
sentences.flatMap(s => s.split(' '));
// ['Hello', 'world', 'foo', 'bar']
// Expand variants
const products = [
{ name: 'shirt', sizes: ['S', 'M', 'L'] },
{ name: 'hat', sizes: ['One Size'] },
];
products.flatMap(p => p.sizes);
// ['S', 'M', 'L', 'One Size']
Why flatMap instead of map + flat? It only flattens one level and avoids creating the intermediate mapped array.
Level 3 — Combining, Slicing & Joining
concat — Merge Arrays
Returns a new array combining the original with other arrays or values. Non-mutating.
const a = [1, 2];
const b = [3, 4];
a.concat(b); // [1, 2, 3, 4]
a.concat(b, [5, 6]); // [1, 2, 3, 4, 5, 6]
a.concat(7, 8); // [1, 2, 7, 8]
// a unchanged: [1, 2]
Spread syntax often reads better:
const combined = [...a, ...b]; // [1, 2, 3, 4]
slice(start, end) — Extract a Shallow Copy
Returns a new array containing elements from start (inclusive) to end (exclusive). Non-mutating.
const arr = ['a', 'b', 'c', 'd', 'e'];
arr.slice(0, 2); // ['a', 'b']
arr.slice(2, 4); // ['c', 'd']
arr.slice(1); // ['b', 'c', 'd', 'e'] — end defaults to length
arr.slice(); // ['a', 'b', 'c', 'd', 'e'] — shallow copy
slice() with no arguments is the idiomatic way to shallow-copy an array:
const copy = arr.slice();
// Same as: [...arr]
Slice With Negative Arguments
Negative indices count from the end. -1 is the last element.
const arr = ['a', 'b', 'c', 'd'];
arr.slice(-2); // ['c', 'd'] — last 2
arr.slice(-3, -1); // ['b', 'c']
arr.slice(1, -1); // ['b', 'c'] — from index 1 to the second-to-last
join(separator) — Array to String
Joins all elements into a string with the separator (default ',').
['a', 'b', 'c'].join(); // 'a,b,c'
['a', 'b', 'c'].join(''); // 'abc'
['a', 'b', 'c'].join(' - '); // 'a - b - c'
[1, 2, null, 3].join(','); // '1,2,,3' — null/undefined become empty string
[].join(','); // ''
Quiz: Copy an Array
Give three different ways to create a shallow copy of const arr = [1, 2, 3].
Answer
const copy1 = arr.slice();
const copy2 = [...arr];
const copy3 = Array.from(arr);
Quiz: Get First N Elements
const data = [10, 20, 30, 40, 50];
// Get first 3 elements
Answer
data.slice(0, 3); // [10, 20, 30]
Level 4 — Searching & Reference Behavior
Arrays Are Objects
Arrays are objects. The indices are string keys:
const arr = ['a', 'b'];
arr[0]; // 'a'
arr['0']; // 'a' — same thing
arr[0] === arr['0']; // true
You can set arbitrary properties (though don’t):
arr.customProp = 'hello';
arr.length; // still 2 — custom props don't affect length
The real implication: arrays have reference semantics:
const a = [1, 2, 3];
const b = a;
b.push(4);
// a is now [1, 2, 3, 4] — same object!
To truly copy: const b = [...a] or b = a.slice().
indexOf(value) / lastIndexOf(value)
Finds the first/last index of a value using strict equality (===). Returns -1 if not found.
const arr = [1, 2, 3, 2, 1];
arr.indexOf(2); // 1
arr.lastIndexOf(2); // 3
arr.indexOf(99); // -1
arr.indexOf(NaN); // -1 — NaN !== NaN
Use findIndex for objects (see Level 5).
includes(value)
Returns boolean. Uses === like indexOf, but returns true/false instead of an index.
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(99); // false
Important distinction:
const obj = { id: 1 };
[obj].includes(obj); // true — same reference
[{ id: 1 }].includes({ id: 1 }); // false — different objects
includes finds NaN (unlike indexOf):
[NaN].includes(NaN); // true
[NaN].indexOf(NaN); // -1
Copying Arrays — Shallow vs Deep
All built-in copy methods create shallow copies:
const original = [{ a: 1 }, { b: 2 }];
const shallow = [...original];
shallow[0].a = 99;
// original[0].a is now 99 — nested objects are shared
Deep copy options:
const deep1 = JSON.parse(JSON.stringify(original));
const deep2 = structuredClone(original); // better: handles Dates, Map, Set, etc.
shift() / unshift() — Front Operations
Revisit from Level 2 with more detail:
const arr = ['a', 'b', 'c'];
arr.shift(); // returns 'a', arr: ['b', 'c']
arr.unshift('x'); // returns 3, arr: ['x', 'b', 'c']
shift and unshift re-index all elements. For large arrays, consider a different data structure or reverse + push/pop.
findIndex(callback) — Find Index by Condition
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
const idx = users.findIndex(u => u.id === 2);
// 1
Replace an item immutably:
const updated = [...users];
const i = updated.findIndex(u => u.id === 2);
if (i !== -1) updated[i] = { ...updated[i], name: 'Robert' };
Level 5 — Finding, Filling & Negative Indexes
find(callback) — Find First Matching Element
Returns the first element where callback returns truthy. Returns undefined if nothing matches. Short-circuits — stops at first match.
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Alice' },
];
users.find(u => u.name === 'Alice');
// { id: 1, name: 'Alice' } — only the FIRST match
users.find(u => u.name === 'Charlie');
// undefined
findLast(callback) / findLastIndex(callback) (ES2023)
Search from the end:
const logs = [
{ level: 'info', msg: 'start' },
{ level: 'error', msg: 'first error' },
{ level: 'info', msg: 'retry' },
{ level: 'error', msg: 'last error' },
];
logs.findLast(l => l.level === 'error');
// { level: 'error', msg: 'last error' }
logs.findLastIndex(l => l.level === 'error');
// 3
Quiz: Implement uniq
Write a function uniq(arr) that returns a new array with duplicates removed.
Solution
const uniq = arr => [...new Set(arr)];
// Or without Set:
const uniq = arr => arr.filter((v, i, a) => a.indexOf(v) === i);
new Array(n) and fill
new Array(n) creates an array of n empty slots:
const arr = new Array(3);
// arr: [empty × 3]
arr.length; // 3
// WARNING: no elements, not even undefined
fill(value, start?, end?) — fills elements with a static value. Mutates.
new Array(3).fill(0);
// [0, 0, 0]
const arr = [1, 2, 3, 4, 5];
arr.fill(0, 1, 4);
// arr: [1, 0, 0, 0, 5]
Create a range:
[...new Array(5)].map((_, i) => i);
// [0, 1, 2, 3, 4]
// Better:
Array.from({ length: 5 }, (_, i) => i);
// [0, 1, 2, 3, 4]
Gotcha: new Array(3).map((_, i) => i) returns [empty × 3] because map skips empty slots. Always .fill() first or use Array.from.
Negative Array Indexes
Standard bracket notation does not support negative indexes — arr[-1] returns undefined.
Use at(index) (ES2022) for negative indexing:
const arr = [10, 20, 30, 40];
arr.at(0); // 10
arr.at(-1); // 40 — last element
arr.at(-2); // 30
arr.at(99); // undefined (no error)
Before at, the idiom was arr[arr.length - 1].
Quiz: Implement find
Write myFind(arr, callback) that works like Array.prototype.find.
Solution
const myFind = (arr, callback) => {
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i], i, arr)) return arr[i];
}
return undefined;
};
Quiz: Rotate Right
Write a function that rotates an array one position to the right.
rotateRight([1, 2, 3, 4]);
// [4, 1, 2, 3]
Solution
const rotateRight = arr => [arr.at(-1), ...arr.slice(0, -1)];
Level 6 — Filtering, Sparse Arrays & Testing
Empty Slots (Sparse Arrays)
Empty slots occur when:
const a = [1, , 3]; // literal with hole
const b = new Array(5); // uninitialized
const c = [1, 2];
c[5] = 3; // c: [1, 2, empty × 3, 3]
Critical difference: Empty slots are not the same as undefined:
const sparse = [1, , 3];
const dense = [1, undefined, 3];
// forEach skips empty slots
sparse.forEach(v => console.log(v)); // 1, 3
dense.forEach(v => console.log(v)); // 1, undefined, 3
// map skips empty slots
sparse.map(v => v); // [1, empty, 3]
dense.map(v => v); // [1, undefined, 3]
// find treats empty slots as undefined
sparse.find(v => v === undefined); // undefined — wait, it stops at index 1? No, find visits all indices and treats empty as undefined
Let me clarify: older methods (forEach, map, filter, reduce, every, some) skip empty slots. Newer methods (find, findIndex, includes, keys, entries, fill, join, toReversed, toSorted) treat empty slots as undefined.
// Older methods skip:
[, 1].forEach(v => console.log(v));
// 1
// Newer methods include:
[, 1].find(v => v === undefined);
// undefined (visits index 0, gets undefined)
[, 1].includes(undefined);
// true
filter(callback) — Keep Matching Elements
Returns a new array with only elements where the callback returns truthy. Non-mutating.
const nums = [1, 2, 3, 4, 5, 6];
nums.filter(n => n % 2 === 0);
// [2, 4, 6]
Common patterns:
const activeUsers = users.filter(u => u.active);
const admins = users.filter(u => u.role === 'admin');
// Remove falsy values (compact)
[0, '', null, undefined, false, 1, 'hello'].filter(Boolean);
// [1, 'hello']
// Filter + map chain
products
.filter(p => p.price > 100)
.map(p => p.name);
Quiz: Fill Dynamically
Create an array [0, 0, 0, 0, 0] of length 5 without writing each zero manually.
Answer
new Array(5).fill(0);
some(callback) and every(callback)
some — returns true if any element matches. Short-circuits on first truthy return.
const nums = [1, 2, 3, 4, 5];
nums.some(n => n > 3); // true (4 is > 3)
nums.some(n => n > 10); // false
every — returns true if all elements match. Short-circuits on first falsy return.
nums.every(n => n > 0); // true
nums.every(n => n < 5); // false (5 is not < 5)
Edge cases:
[].some(() => {}); // false — no elements to test
[].every(() => {}); // true — vacuous truth
Quiz: Even Numbers
Use filter to get even numbers from [1, 2, 3, 4, 5, 6].
Answer
[1, 2, 3, 4, 5, 6].filter(n => n % 2 === 0);
// [2, 4, 6]
Quiz: Implement none
Write none(arr, callback) that returns true if no element matches.
Solution
const none = (arr, callback) => !arr.some(callback);
// Or:
const none = (arr, callback) => arr.every(v => !callback(v));
Quiz: Implement filter with forEach
Implement filter using forEach.
Solution
const myFilter = (arr, callback) => {
const result = [];
arr.forEach((el, i, a) => {
if (callback(el, i, a)) result.push(el);
});
return result;
};
Level 7 — Sorting, Reducing & Reversing
Quiz: Implement compact
Write a function that removes all falsy values from an array.
Solution
const compact = arr => arr.filter(Boolean);
compact([0, 1, false, 2, '', 3, null, undefined, NaN]);
// [1, 2, 3]
sort(compareFunction) — ⚠️ Mutates
sort() without a compare function converts elements to strings and sorts lexicographically:
[1, 10, 2, 20].sort();
// [1, 10, 2, 20] — WRONG for numbers!
Always provide a compare function. The function returns:
- negative →
abeforeb - positive →
bbeforea - zero → unchanged order (not guaranteed across engines)
// Numbers ascending
[3, 1, 4, 1, 5].sort((a, b) => a - b);
// [1, 1, 3, 4, 5]
// Numbers descending
[3, 1, 4, 1, 5].sort((a, b) => b - a);
// [5, 4, 3, 1, 1]
// Strings (locale-aware)
names.sort((a, b) => a.localeCompare(b));
// Objects by field
people.sort((a, b) => a.age - b.age);
// Multiple fields
people.sort((a, b) =>
a.lastName.localeCompare(b.lastName) ||
a.firstName.localeCompare(b.firstName)
);
sort mutates the original. Always copy first for immutable code:
const sorted = [...arr].sort((a, b) => a - b);
// Or ES2023:
const sorted = arr.toSorted((a, b) => a - b);
toSorted(compareFunction) (ES2023)
Non-mutating version of sort:
const original = [3, 1, 4, 1, 5];
const sorted = original.toSorted((a, b) => a - b);
// sorted: [1, 1, 3, 4, 5]
// original unchanged: [3, 1, 4, 1, 5]
Quiz: Has Null
Use some to check if [1, null, 3] contains null.
Answer
[1, null, 3].some(v => v === null); // true
reduce(callback, initialValue) — The Swiss Army Knife
The most flexible array method. Reduces the array to a single value by accumulating.
Signature: reduce((accumulator, element, index, array) => nextAccumulator, initialValue)
const nums = [1, 2, 3, 4, 5];
// Sum
nums.reduce((acc, n) => acc + n, 0);
// 15
// Product
nums.reduce((acc, n) => acc * n, 1);
// 120
// Max
nums.reduce((acc, n) => Math.max(acc, n), -Infinity);
// 5
Without initialValue: reduce uses the first element as the accumulator and starts from index 1.
[1, 2, 3].reduce((acc, n) => acc + n);
// 6 — same as with 0, but only works for non-empty arrays
⚠️ Always provide an initial value — it’s clearer and avoids the TypeError on empty arrays:
[].reduce((acc, n) => acc + n, 0); // 0 — safe
[].reduce((acc, n) => acc + n); // TypeError!
Common patterns:
// Group by
const byDept = people.reduce((groups, p) => {
groups[p.dept] = groups[p.dept] || [];
groups[p.dept].push(p);
return groups;
}, {});
// Count occurrences
const counts = words.reduce((acc, w) => {
acc[w] = (acc[w] || 0) + 1;
return acc;
}, {});
// Tally
const colors = ['red', 'blue', 'red', 'green', 'blue', 'red'];
colors.reduce((tally, color) => {
tally[color] = (tally[color] || 0) + 1;
return tally;
}, {});
// { red: 3, blue: 2, green: 1 }
Object.groupBy(array, keyFn) (ES2024)
Built-in grouping — cleaner than reduce for this specific use case:
const grouped = Object.groupBy(products, p => p.category);
// {
// fruit: [{ name: 'Apple' }, { name: 'Banana' }],
// vegetable: [{ name: 'Carrot' }]
// }
reverse() — ⚠️ Mutates
Reverses in place:
const arr = [1, 2, 3];
arr.reverse();
// arr: [3, 2, 1]
// returns [3, 2, 1]
Non-mutating alternatives:
const reversed = [...arr].reverse();
// Or ES2023:
const reversed = arr.toReversed();
Quiz: All True
Check if [true, true, false, true] has all true values.
Answer
[true, true, false, true].every(v => v === true);
// Or simply:
[true, true, false, true].every(Boolean);
Quiz: Sort by Word Length
const words = ['apple', 'hi', 'banana', 'cat'];
// Sort by word length ascending
Answer
[...words].sort((a, b) => a.length - b.length);
// ['hi', 'cat', 'apple', 'banana']
Level 8 — Advanced Reduce, ReduceRight & Immutable Updates
Quiz: Implement filter with reduce
Solution
const filter = (arr, callback) =>
arr.reduce((acc, el, i, a) => {
if (callback(el, i, a)) acc.push(el);
return acc;
}, []);
Quiz: Sum Squares of Odds
Chain filter, map, and reduce to sum the squares of odd numbers from [1, 2, 3, 4, 5].
Solution
const sumSquaresOfOdds = arr =>
arr
.filter(n => n % 2 !== 0)
.map(n => n * n)
.reduce((a, b) => a + b, 0);
sumSquaresOfOdds([1, 2, 3, 4, 5]); // 1 + 9 + 25 = 35
Single reduce version:
arr.reduce((acc, n) => (n % 2 !== 0 ? acc + n * n : acc), 0);
Quiz: Implement join with reduce
Solution
const join = (arr, separator = ',') =>
arr.reduce((acc, el, i) =>
i === 0 ? String(el) : `${acc}${separator}${String(el)}`
, '');
reduceRight(callback, initialValue)
Like reduce but iterates right-to-left:
const flattened = [[1, 2], [3, 4], [5]].reduceRight(
(acc, arr) => acc.concat(arr), []
);
// [5, 3, 4, 1, 2]
Useful for:
- Reversing order of operations
- Right-associative reductions (e.g., exponentiation chains)
Quiz: Implement reverse with reduceRight
Solution
const reverse = arr =>
arr.reduceRight((acc, el) => (acc.push(el), acc), []);
ES2023 Immutable Methods Summary
All return new arrays, none mutate:
| Mutating | Immutable equivalent |
|---|---|
sort() |
toSorted() |
reverse() |
toReversed() |
splice() |
toSpliced() |
arr[index] = val |
with(index, val) |
const arr = ['a', 'b', 'c', 'd'];
arr.toReversed(); // ['d', 'c', 'b', 'a']
arr.toSorted(); // ['a', 'b', 'c', 'd']
arr.toSpliced(1, 2, 'x'); // ['a', 'x', 'd']
arr.with(1, 'z'); // ['a', 'z', 'c', 'd']
// arr unchanged
Iterators: keys(), values(), entries()
const arr = ['x', 'y', 'z'];
[...arr.keys()]; // [0, 1, 2]
[...arr.values()]; // ['x', 'y', 'z']
[...arr.entries()]; // [[0, 'x'], [1, 'y'], [2, 'z']]
Useful with for...of:
for (const [index, value] of arr.entries()) {
console.log(index, value);
}
Appendix A: All Array Methods at a Glance
Static Methods
| Method | Description |
|---|---|
Array.from(iterable, mapFn?) |
Creates array from iterable or array-like |
Array.fromAsync(iterable, mapFn?) |
Async version of from |
Array.isArray(value) |
Checks if value is an array |
Array.of(...elements) |
Creates array from arguments |
Instance Methods — Mutating
| Method | Description | Return value |
|---|---|---|
copyWithin(target, start, end?) |
Copies sequence within array | Mutated array |
fill(value, start?, end?) |
Fills with static value | Mutated array |
pop() |
Removes last element | Removed element |
push(...items) |
Appends elements | New length |
reverse() |
Reverses in place | Mutated array |
shift() |
Removes first element | Removed element |
sort(compareFn?) |
Sorts in place | Mutated array |
splice(start, deleteCount?, ...items) |
Add/remove at index | Removed elements |
unshift(...items) |
Prepends elements | New length |
Instance Methods — Non-Mutating (Accessors)
| Method | Description |
|---|---|
at(index) |
Element at index (supports negatives) |
concat(...values) |
Merged new array |
includes(value, fromIndex?) |
Boolean membership test |
indexOf(value, fromIndex?) |
First index or -1 |
join(separator?) |
String from elements |
lastIndexOf(value, fromIndex?) |
Last index or -1 |
slice(start?, end?) |
Shallow copy segment |
toString() |
Comma-separated string |
toLocaleString() |
Locale-aware string |
Instance Methods — Iteration (Non-Mutating)
| Method | Description |
|---|---|
every(callback) |
All match? (short-circuits) |
filter(callback) |
New array of matches |
find(callback) |
First match or undefined |
findIndex(callback) |
First match index or -1 |
findLast(callback) |
Last match or undefined |
findLastIndex(callback) |
Last match index or -1 |
flat(depth?) |
Flattened new array |
flatMap(callback) |
Map then flatten 1 level |
forEach(callback) |
Side effects (returns undefined) |
map(callback) |
Transformed new array |
reduce(callback, initial?) |
Accumulated value (L-to-R) |
reduceRight(callback, initial?) |
Accumulated value (R-to-L) |
some(callback) |
Any match? (short-circuits) |
Instance Methods — ES2023+ (Non-Mutating)
| Method | Description |
|---|---|
toReversed() |
Reversed copy |
toSorted(compareFn?) |
Sorted copy |
toSpliced(start, deleteCount?, ...items) |
Spliced copy |
with(index, value) |
Element-replaced copy |
Instance Methods — Iterators
| Method | Description |
|---|---|
entries() |
Iterator of [index, value] pairs |
keys() |
Iterator of indices |
values() |
Iterator of values |
[Symbol.iterator]() |
Same as values() |
Appendix B: Common Patterns Cheat Sheet
// Remove duplicates
const unique = [...new Set(arr)];
// Remove duplicates by property
const uniqueById = arr.filter(
(item, i, a) => a.findIndex(t => t.id === item.id) === i
);
// Intersection
const intersection = a.filter(x => b.includes(x));
// Difference
const diff = a.filter(x => !b.includes(x));
// Chunk into groups
const chunk = (arr, n) =>
Array.from({ length: Math.ceil(arr.length / n) }, (_, i) =>
arr.slice(i * n, i * n + n)
);
// Zip
const zip = (a, b) => a.map((item, i) => [item, b[i]]);
// Flatten one level
const flatten = arr => [].concat(...arr);
// Partition
const partition = (arr, callback) =>
arr.reduce(
([pass, fail], el) =>
callback(el) ? [[...pass, el], fail] : [pass, [...fail, el]],
[[], []]
);
// Shuffle (Fisher-Yates)
const shuffle = arr => {
const result = [...arr];
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return result;
};
Appendix C: Performance & Gotchas
When NOT to use array methods
| Situation | Prefer |
|---|---|
| Need to break early | for...of or some/every |
| Very large arrays (>100k) | for loop (3-10x faster) |
Sparse arrays with map |
Array.from or fill first |
Need early return from forEach |
for...of or find |
array.every() and empty arrays
[].every(fn) returns true (vacuous truth). [].some(fn) returns false.
NaN behavior
[NaN].includes(NaN); // true
[NaN].indexOf(NaN); // -1
[NaN].find(n => Number.isNaN(n)); // NaN
The thisArg parameter
All iterative methods accept a second argument for this inside the callback:
const checker = { threshold: 5 };
[1, 2, 6, 3].filter(function(el) {
return el > this.threshold;
}, checker);
// [6]
Arrow functions ignore thisArg — they capture this lexically.
Memoized length
Iterative methods memorize length before looping. Mutations that change length during iteration produce surprising results — avoid this pattern.
Course structure inspired by Execute Program’s JavaScript Arrays curriculum. Content expanded with MDN documentation, practical patterns, and deep-dive explanations.