πŸ› οΈ 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

GoalBest MethodNotes
Run side effectsforEachNo return value
Transform each elementmapReturns new array
Keep matching itemsfilterReturns new array
Collapse to one valuereduceSum, group, count
First matchfindReturns element or undefined
Index of first matchfindIndexReturns index or -1
Check ALL matcheveryShort-circuits on false
Check ANY matchsomeShort-circuits on true
Flatten nestedflat(depth)flat(Infinity) for all
Flatten + transformflatMapOne-pass map+flat(1)
Get portionslice(s,e)Does not mutate
Remove/insert middlesplice(s,d,..items)Mutates!
Check membershipincludesHandles NaN
Find index of valueindexOf-1 if not found
Sortsort(compareFn)Always provide compareFn for numbers
Add to endpushO(1), mutates
Add to startunshiftO(n), mutates
Remove from endpopO(1), mutates
Remove from startshiftO(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
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 avoid undefined groups

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: max and second. If num > max: second = max, max = num. Else if num > 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: push arr.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]