π οΈ JavaScript Array Methods β Complete Guide
Index: Methods Index | Parent: JS Array Index
1. Mutating Methods
These methods change the original array.
push / pop β Add/Remove from End O(1)
const arr = [1, 2, 3];
arr.push(4); // [1,2,3,4] β returns new length: 4
arr.push(5, 6); // [1,2,3,4,5,6]
const last = arr.pop(); // returns 6, arr = [1,2,3,4,5]
shift / unshift β Add/Remove from Start O(n)
const arr = [1, 2, 3];
arr.unshift(0); // [0,1,2,3] β add to front, returns new length
const first = arr.shift(); // removes 0, arr = [1,2,3]
splice β Insert / Delete / Replace O(n)
// splice(start, deleteCount, ...items)
const arr = ['a','b','c','d'];
// Delete
arr.splice(1, 2); // removes 'b','c', arr = ['a','d']
// Insert (no deletion)
arr.splice(1, 0, 'X', 'Y'); // arr = ['a','X','Y','d']
// Replace
arr.splice(1, 1, 'Z'); // replace 1 element: ['a','Z','Y','d']
// splice returns removed elements
const removed = ['a','b','c','d'].splice(1, 2); // ['b','c']
sort β Sort In-Place O(n log n)
// β DEFAULT sorts as strings!
[10, 9, 2, 100].sort(); // [10, 100, 2, 9] β WRONG for numbers
// Correct numeric sort
[10, 9, 2, 100].sort((a, b) => a - b); // [2, 9, 10, 100] ascending
[10, 9, 2, 100].sort((a, b) => b - a); // [100, 10, 9, 2] descending
// Sort strings
['banana','apple','cherry'].sort(); // ['apple','banana','cherry']
['banana','apple','cherry'].sort((a,b) => b.localeCompare(a)); // desc
// Sort objects
const people = [{name:'Bob',age:30},{name:'Alice',age:25}];
people.sort((a, b) => a.age - b.age); // by age ascending
people.sort((a, b) => a.name.localeCompare(b.name)); // by name
reverse β Reverse In-Place O(n)
const arr = [1, 2, 3, 4, 5];
arr.reverse(); // [5,4,3,2,1] β mutates original!
// Non-mutating reverse
const reversed = [...arr].reverse();
fill β Fill with Value O(n)
new Array(5).fill(0); // [0,0,0,0,0]
[1,2,3,4,5].fill(0, 2, 4); // [1,2,0,0,5] β fill index 2-3
[1,2,3].fill(9); // [9,9,9]
copyWithin β Copy Portion In-Place
// copyWithin(target, start, end)
[1,2,3,4,5].copyWithin(0, 3); // [4,5,3,4,5] β copy idx3-4 to idx0
2. Iteration Methods
These methods do not mutate the original (return new array or value).
forEach β Iterate (No Return) O(n)
const arr = [1, 2, 3];
arr.forEach((value, index, array) => {
console.log(`${index}: ${value}`);
});
// Cannot break out of forEach β use for...of if you need break
// Returns undefined
map β Transform Each Element O(n)
const nums = [1, 2, 3, 4];
const doubled = nums.map(x => x * 2); // [2,4,6,8]
const strings = nums.map(x => x.toString()); // ['1','2','3','4']
// Map with index
const indexed = nums.map((val, i) => `${i}:${val}`); // ['0:1','1:2',...]
// Map objects
const users = [{name:'Alice',age:25},{name:'Bob',age:30}];
const names = users.map(u => u.name); // ['Alice','Bob']
filter β Keep Matching Elements O(n)
const nums = [1, 2, 3, 4, 5, 6];
const evens = nums.filter(x => x % 2 === 0); // [2,4,6]
const odds = nums.filter(x => x % 2 !== 0); // [1,3,5]
const gt3 = nums.filter(x => x > 3); // [4,5,6]
const unique = nums.filter((v, i, a) => a.indexOf(v) === i); // dedup
// filter + map chain
const result = nums
.filter(x => x % 2 === 0)
.map(x => x * 10); // [20,40,60]
reduce β Accumulate to Single Value O(n)
const nums = [1, 2, 3, 4, 5];
// Sum
const sum = nums.reduce((acc, cur) => acc + cur, 0); // 15
// Product
const product = nums.reduce((acc, cur) => acc * cur, 1); // 120
// Max value
const max = nums.reduce((acc, cur) => acc > cur ? acc : cur, -Infinity);
// Count frequencies
const freq = ['a','b','a','c','b','a'].reduce((acc, ch) => {
acc[ch] = (acc[ch] || 0) + 1;
return acc;
}, {}); // {a:3, b:2, c:1}
// Group by
const grouped = [{type:'fruit',name:'apple'},{type:'veg',name:'carrot'},{type:'fruit',name:'banana'}]
.reduce((acc, item) => {
(acc[item.type] = acc[item.type] || []).push(item.name);
return acc;
}, {}); // {fruit:['apple','banana'], veg:['carrot']}
// Flatten array
const flat = [[1,2],[3,4],[5]].reduce((acc, arr) => acc.concat(arr), []);
// [1,2,3,4,5]
find / findIndex β First Match O(n)
const users = [{id:1,name:'Alice'},{id:2,name:'Bob'},{id:3,name:'Carol'}];
const user = users.find(u => u.id === 2); // {id:2,name:'Bob'}
const idx = users.findIndex(u => u.id === 2); // 1
// findLast / findLastIndex (ES2023)
const arr = [1, 2, 3, 4, 3, 2];
const lastTwo = arr.findLast(x => x === 2); // 2 (at index 5)
const lastTwoIdx = arr.findLastIndex(x => x === 2); // 5
every / some β Boolean Checks O(n)
const nums = [2, 4, 6, 8];
nums.every(x => x % 2 === 0); // true β ALL are even
nums.some(x => x > 5); // true β AT LEAST ONE is > 5
[1, 3, 5].every(x => x % 2 === 0); // false
[1, 3, 5].some(x => x % 2 === 0); // false
// Practical examples
const allAdults = users.every(u => u.age >= 18);
const hasAdmin = users.some(u => u.role === 'admin');
flat / flatMap O(n)
// flat(depth) β flatten nested arrays
[1, [2, 3], [4, [5, 6]]].flat(); // [1,2,3,4,[5,6]] β depth 1
[1, [2, [3, [4]]]].flat(Infinity); // [1,2,3,4] β all levels
// flatMap = map + flat(1) in one pass
const sentences = ['Hello World', 'Foo Bar'];
const words = sentences.flatMap(s => s.split(' '));
// ['Hello','World','Foo','Bar']
// Practical: expand each item to multiple
const doubled = [1,2,3].flatMap(x => [x, x*2]); // [1,2,2,4,3,6]
3. Non-Mutating Utility Methods
slice β Copy Portion O(n)
const arr = [1, 2, 3, 4, 5];
arr.slice(1, 3); // [2,3] β from index 1 up to (not including) 3
arr.slice(2); // [3,4,5] β from index 2 to end
arr.slice(-2); // [4,5] β last 2 elements
arr.slice(); // [1,2,3,4,5] β clone the array
concat β Merge Arrays O(n)
[1,2].concat([3,4], [5,6]); // [1,2,3,4,5,6]
[1,2].concat(3, 4); // [1,2,3,4]
// Prefer spread for clarity
const merged = [...arr1, ...arr2];
join β Array to String O(n)
['a','b','c'].join(''); // 'abc'
['a','b','c'].join(', '); // 'a, b, c'
[1,2,3].join('-'); // '1-2-3'
indexOf / lastIndexOf O(n)
const arr = [1, 2, 3, 2, 1];
arr.indexOf(2); // 1 (first occurrence)
arr.lastIndexOf(2); // 3 (last occurrence)
arr.indexOf(9); // -1 (not found)
arr.indexOf(2, 2); // 3 (search from index 2)
includes O(n)
[1, 2, 3].includes(2); // true
[1, 2, NaN].includes(NaN); // true β unlike indexOf which uses ===
[1, 2, 3].includes(4); // false
at β Access with Negative Index O(1)
const arr = [10, 20, 30, 40];
arr.at(0); // 10
arr.at(-1); // 40 (last)
arr.at(-2); // 30
entries / keys / values β Iterators
const arr = ['a','b','c'];
for (const [i, v] of arr.entries()) {
console.log(i, v); // 0 'a', 1 'b', 2 'c'
}
[...arr.keys()]; // [0,1,2]
[...arr.values()]; // ['a','b','c']
4. Static Methods
// Array.isArray β check if value is array
Array.isArray([1,2,3]); // true
Array.isArray('hello'); // false
Array.isArray({0:'a'}); // false
// Array.from β from iterable / array-like + optional map fn
Array.from('abc'); // ['a','b','c']
Array.from({length:5}, (_, i) => i * 2); // [0,2,4,6,8]
Array.from(new Map([['a',1],['b',2]])); // [['a',1],['b',2]]
Array.from(new Set([1,2,3])); // [1,2,3]
Array.from(document.querySelectorAll('p')); // NodeList β Array
// Array.of β create array from arguments (unlike Array() single arg)
Array.of(7); // [7] vs new Array(7) = [empty Γ 7]
Array.of(1, 2, 3); // [1,2,3]
5. Method Chaining
const orders = [
{id:1, product:'Apple', price:1.5, qty:10, active:true},
{id:2, product:'Banana', price:0.5, qty:0, active:false},
{id:3, product:'Cherry', price:3.0, qty:5, active:true},
{id:4, product:'Date', price:5.0, qty:2, active:true},
];
const report = orders
.filter(o => o.active && o.qty > 0) // only active with stock
.map(o => ({ // compute total
...o,
total: o.price * o.qty
}))
.sort((a, b) => b.total - a.total) // sort by total desc
.slice(0, 3) // top 3
.map(o => `${o.product}: $${o.total}`); // format
// ['Apple: $15', 'Cherry: $15', 'Date: $10']
6. When to Use Which
| Goal | Best Method | Notes |
|---|---|---|
| Run side effects | forEach | No return value |
| Transform each element | map | Returns new array |
| Keep matching items | filter | Returns new array |
| Collapse to one value | reduce | Sum, group, count |
| First match | find | Returns element or undefined |
| Index of first match | findIndex | Returns index or -1 |
| Check ALL match | every | Short-circuits on false |
| Check ANY match | some | Short-circuits on true |
| Flatten nested | flat(depth) | flat(Infinity) for all |
| Flatten + transform | flatMap | One-pass map+flat(1) |
| Get portion | slice(s,e) | Does not mutate |
| Remove/insert middle | splice(s,d,..items) | Mutates! |
| Check membership | includes | Handles NaN |
| Find index of value | indexOf | -1 if not found |
| Sort | sort(compareFn) | Always provide compareFn for numbers |
| Add to end | push | O(1), mutates |
| Add to start | unshift | O(n), mutates |
| Remove from end | pop | O(1), mutates |
| Remove from start | shift | O(n), mutates |
7. Interview Questions
Q1. Flatten a Deeply Nested Array [M][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Nested array of arbitrary depth = recursion.
Step 2 β JS built-in:
arr.flat(Infinity)handles all depths β mention this first, then explain the manual approach.Step 3 β Manual recursive:
For each element: if
Array.isArray(item), recurse; else push to result. Spread the recursive result into the accumulator.Step 4 β Edge cases:
- Empty nested arrays: ignored
- Already flat: returns copy with same values
Way of Thinking:
- Built-in:
flat(Infinity)for all levels - Manual: recursion β if element is array, recurse; else push to result
// Built-in
const nested = [1, [2, [3, [4, [5]]]]];
nested.flat(Infinity); // [1,2,3,4,5]
// Manual recursive
function flatten(arr) {
const result = [];
for (const item of arr) {
if (Array.isArray(item)) {
result.push(...flatten(item)); // spread recursive result
} else {
result.push(item);
}
}
return result;
}
// Using reduce (elegant)
const flattenReduce = arr => arr.reduce(
(acc, item) => acc.concat(Array.isArray(item) ? flattenReduce(item) : item),
[]
);
console.log(flatten([1,[2,[3,[4]]]])); // [1,2,3,4]
Q2. Group Array by Key [M][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Group by field = accumulate into a hashmap keyed by that field.
Step 2 β Algorithm using reduce:
Start with empty object
{}. For each item: get the group key, create array if missing, push item.Step 3 β Flexible design:
Accept either a string field name or a function β this makes it reusable (group by computed values like odd/even).
Step 4 β Edge cases:
- Missing key in item: use
item[key] ?? 'unknown'to avoidundefinedgroups
Way of Thinking: Use reduce to build an object where each key holds an array of matching items. Like PHP's groupBy.
function groupBy(arr, key) {
return arr.reduce((groups, item) => {
const val = typeof key === 'function' ? key(item) : item[key];
(groups[val] = groups[val] || []).push(item);
return groups;
}, {});
}
const people = [
{name:'Alice', dept:'Engineering'},
{name:'Bob', dept:'Marketing'},
{name:'Carol', dept:'Engineering'},
];
console.log(groupBy(people, 'dept'));
// { Engineering: [{name:'Alice',...},{name:'Carol',...}], Marketing: [{name:'Bob',...}] }
// By function
groupBy([1,2,3,4,5,6], x => x % 2 === 0 ? 'even' : 'odd');
// { odd:[1,3,5], even:[2,4,6] }
Q3. Find Second Largest Number [M][FB]
π§ How to Approach This
Step 1 β Simple approach:
Deduplicate with Set, sort descending, take index 1. O(n log n). Valid shorthand.
Step 2 β Optimal: single pass O(n):
Track two variables:
maxandsecond. Ifnum > max: second = max, max = num. Else ifnum > second && num !== max: second = num.Step 3 β Why
num !== max?Prevents treating a duplicate of max as a valid second largest.
Step 4 β Edge cases:
- All same values: return null (no true second largest)
- Less than 2 elements: return null
Way of Thinking: Single pass tracking two variables: max and secondMax. Don't use sort (that's O(n log n)).
function secondLargest(arr) {
let max = -Infinity, second = -Infinity;
for (const num of arr) {
if (num > max) {
second = max;
max = num;
} else if (num > second && num !== max) {
second = num;
}
}
return second === -Infinity ? null : second;
}
console.log(secondLargest([3, 1, 4, 1, 5, 9, 2, 6])); // 6
// Alternative: Set + sort (simpler but O(n log n))
const secondLargestSimple = arr =>
[...new Set(arr)].sort((a,b) => b-a)[1] ?? null;
Q4. Chunk Array into Groups of N [M][L]
π§ How to Approach This
Step 1 β Recognize the pattern:
Pagination / batching = slice array in fixed windows of size n.
Step 2 β Algorithm:
Loop with step size
n. On each iteration: pusharr.slice(i, i+n)to result.Step 3 β Alternative:
Array.from({length: ceil(n/size)}, (_, i) => arr.slice(isize, isize+size))β same logic, more declarative.Step 4 β Edge cases:
- Last chunk may be smaller than n (slice handles this automatically)
- size = 0: throw error to avoid infinite loop
Way of Thinking: Slice the array in windows of size n using a loop. Common for pagination.
function chunk(arr, size) {
const result = [];
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
}
// Using Array.from
const chunk2 = (arr, size) =>
Array.from({length: Math.ceil(arr.length / size)}, (_, i) =>
arr.slice(i * size, i * size + size)
);
console.log(chunk([1,2,3,4,5,6,7], 3)); // [[1,2,3],[4,5,6],[7]]
Q5. Intersection of Two Arrays [E][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Find common elements = convert one array to a Set for O(1) lookup, filter the other.
Step 2 β Brute force:
Nested loops: for each element in arr1, check if in arr2 β O(nΓm). Too slow.
Step 3 β Optimal: O(n+m):
Set(arr2)built in O(m). Then filter arr1:arr1.filter(x => set.has(x))in O(n).Step 4 β Unique vs count-based:
- "Unique intersection": wrap filter result in
new Set()then spread- "Count-based": use frequency maps and take min count for each element
Step 5 β Edge cases:
- Empty array: intersection is empty
- All same elements: intersection = those elements (up to count)
Way of Thinking: Convert one array to a Set for O(1) lookup, then filter the other.
function intersection(arr1, arr2) {
const set = new Set(arr2);
return arr1.filter(x => set.has(x));
}
// Unique intersection
function intersectionUnique(arr1, arr2) {
const set = new Set(arr2);
return [...new Set(arr1.filter(x => set.has(x)))];
}
console.log(intersection([1,2,2,3,4], [2,3,5])); // [2,2,3]
console.log(intersectionUnique([1,2,2,3,4], [2,3,5])); // [2,3]