Intermediate3 questionsFull Guide

JavaScript Array Interview Questions

Array methods are asked in every JavaScript interview. Master map, filter, reduce, destructuring, and the new ES2023 immutable methods.

The Mental Model

Picture a numbered locker room. Each locker has a number starting from 0, and you can put anything inside — a number, a string, another locker room, a function. The locker room keeps track of how many lockers are in use (length). You can add new lockers at the end, remove from the front, rearrange them, or look at all of them in sequence. But JavaScript arrays are smarter than lockers. They come with an entire toolkit of built-in operations — transform every item (map), keep only some (filter), collapse to one value (reduce), find a specific one (find), sort them, combine them, split them. They also have a critical quirk: they are objects. The indices are just keys that happen to be integers. And mutation — changing the array in place versus creating a new one — is a distinction that shapes entire codebases. The key insight: knowing which array methods mutate the original and which return a new one is the single most important practical knowledge about arrays. It determines whether your code has bugs in shared state, and it determines whether React re-renders happen when they should.

The Explanation

Creating arrays

// Literal — always prefer this
const nums = [1, 2, 3]
const mixed = [1, 'two', true, null, { x: 1 }, [2, 3]]

// Array.from — convert any iterable or array-like to a real array
Array.from('hello')           // ['h', 'e', 'l', 'l', 'o']
Array.from({ length: 5 }, (_, i) => i)  // [0, 1, 2, 3, 4]
Array.from(new Set([1, 2, 2, 3]))        // [1, 2, 3] — deduplicate
Array.from(new Map([['a', 1]]))          // [['a', 1]]
Array.from(document.querySelectorAll('div'))  // NodeList → real array

// Array.of — creates array from arguments (unlike Array() which has quirks)
Array.of(3)    // [3] — one element
Array(3)       // [,,] — sparse array with 3 empty slots (not [3]!)
Array(1, 2, 3) // [1, 2, 3]

// Spread from any iterable
const copy = [...nums]
const merged = [...arr1, ...arr2, extraItem]

Mutating methods — modify the original array

const arr = [1, 2, 3, 4, 5]

// Add / remove
arr.push(6)        // adds to end → returns new length → [1,2,3,4,5,6]
arr.pop()          // removes from end → returns removed element
arr.unshift(0)     // adds to start → returns new length (SLOW on large arrays)
arr.shift()        // removes from start → returns removed element (SLOW)

// splice — the Swiss Army knife of mutation
arr.splice(2, 1)            // at index 2, remove 1 → returns removed elements
arr.splice(1, 2, 'a', 'b')  // at index 1, remove 2, insert 'a','b'
arr.splice(2, 0, 'inserted') // at index 2, remove 0, insert 'inserted'

// sort — mutates the original, returns same array
[3, 1, 4, 1, 5].sort()             // [1, 1, 3, 4, 5] — lexicographic by default
[10, 9, 2, 100].sort()             // [10, 100, 2, 9] — string sort: WRONG for numbers!
[10, 9, 2, 100].sort((a, b) => a - b) // [2, 9, 10, 100] — numeric ascending
[10, 9, 2, 100].sort((a, b) => b - a) // [100, 10, 9, 2] — numeric descending

// reverse — mutates, returns same array
[1, 2, 3].reverse()  // [3, 2, 1]

// fill — fills elements with a value
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 from index 2 to 4

Non-mutating methods — return a new array or value

const arr = [1, 2, 3, 4, 5]

// Transforming
arr.map(x => x * 2)          // [2, 4, 6, 8, 10] — same length
arr.filter(x => x % 2 === 0) // [2, 4] — shorter or same length
arr.reduce((acc, x) => acc + x, 0)  // 15 — single value

// Copying / slicing
arr.slice()          // [1, 2, 3, 4, 5] — full copy
arr.slice(1, 3)      // [2, 3] — from index 1 up to (not including) 3
arr.slice(-2)        // [4, 5] — last 2

// Combining
arr.concat([6, 7])   // [1, 2, 3, 4, 5, 6, 7]
[...arr, 6, 7]       // same — spread preferred

// Joining
arr.join(', ')       // '1, 2, 3, 4, 5'
arr.join('')         // '12345'

// Flattening
[[1, 2], [3, 4]].flat()          // [1, 2, 3, 4]
[1, [2, [3, [4]]]].flat(Infinity) // [1, 2, 3, 4] — fully flatten
arr.flatMap(x => [x, x * 2])    // [1,2, 2,4, 3,6...] — map then flat(1)

// ES2023 — non-mutating sort and reverse (return copies)
arr.toSorted((a, b) => a - b)  // new sorted array — original unchanged
arr.toReversed()                // new reversed array — original unchanged
arr.toSpliced(2, 1, 'new')     // new spliced array — original unchanged
arr.with(2, 'replaced')        // new array with index 2 changed — original unchanged

Searching and testing

const users = [
  { id: 1, name: 'Alice', active: true  },
  { id: 2, name: 'Bob',   active: false },
  { id: 3, name: 'Carol', active: true  },
]

// Finding
users.find(u => u.id === 2)          // { id: 2, name: 'Bob', active: false }
users.findIndex(u => u.id === 2)     // 1
users.findLast(u => u.active)        // { id: 3, name: 'Carol', active: true } (ES2023)
users.findLastIndex(u => u.active)   // 2

// Includes / indexOf
[1, 2, 3].includes(2)         // true
[1, 2, NaN].includes(NaN)     // true — uses SameValueZero (unlike ===)
[1, 2, 3].indexOf(2)          // 1
[1, 2, 3].indexOf(99)         // -1 — not found
[1, 2, 3].lastIndexOf(2)      // 1

// Testing
users.every(u => u.id > 0)    // true  — all pass
users.some(u => !u.active)    // true  — at least one fails
users.every(u => u.active)    // false — not all active

Destructuring arrays

const [first, second, ...rest] = [1, 2, 3, 4, 5]
// first = 1, second = 2, rest = [3, 4, 5]

// Skip elements with commas
const [,, third] = [1, 2, 3, 4]   // third = 3

// Default values
const [a = 10, b = 20] = [1]      // a = 1, b = 20

// Swap variables without temp
let x = 1, y = 2
;[x, y] = [y, x]                  // x = 2, y = 1

// From function return
function getRange() { return [0, 100] }
const [min, max] = getRange()

Common patterns and pitfalls

// Removing duplicates
const unique = [...new Set([1, 2, 2, 3, 3, 3])]  // [1, 2, 3]

// Flattening with flatMap
const sentences = ['Hello world', 'Foo bar']
const words = sentences.flatMap(s => s.split(' '))
// ['Hello', 'world', 'Foo', 'bar']

// Group by (ES2024 / via reduce)
const grouped = users.reduce((acc, user) => {
  const key = user.active ? 'active' : 'inactive'
  ;(acc[key] ??= []).push(user)
  return acc
}, {})
// Object.groupBy(users, u => u.active ? 'active' : 'inactive') — ES2024

// ❌ sort() without comparator — the classic bug
[10, 9, 100, 2].sort()              // [10, 100, 2, 9] — string comparison!
[10, 9, 100, 2].sort((a, b) => a-b) // [2, 9, 10, 100] ✓

// ❌ Using delete to remove an element — leaves holes
const arr = [1, 2, 3]
delete arr[1]    // [1, empty, 3] — length is still 3! Use splice instead
arr.splice(1, 1) // [1, 3] ✓

// ❌ Mutating in map — always return new values
users.map(u => { u.active = false; return u })  // mutates original objects!
users.map(u => ({ ...u, active: false }))        // ✓ creates new objects

Mutating vs non-mutating — the complete reference

// MUTATE the original array:
push, pop, shift, unshift, splice, sort, reverse, fill, copyWithin

// Return NEW array or value (original unchanged):
map, filter, reduce, reduceRight, slice, concat, flat, flatMap,
find, findIndex, findLast, findLastIndex, indexOf, lastIndexOf,
includes, every, some, forEach, join, entries, keys, values,
toSorted, toReversed, toSpliced, with  // ES2023 — explicit non-mutating versions

// Key rule for React: never use mutating methods directly on state arrays
// Wrong:  state.push(item); setState(state)  — same reference, no re-render
// Right:  setState([...state, item])         — new array, triggers re-render

Common Misconceptions

⚠️

Many devs think sort() without a comparator sorts numbers correctly — but actually sort() converts elements to strings first and sorts lexicographically. [10, 9, 2, 100].sort() produces [10, 100, 2, 9] because '100' comes before '2' alphabetically. Always pass a comparator for numbers: .sort((a, b) => a - b).

⚠️

Many devs think splice and slice are interchangeable — but actually they are fundamentally different. slice(start, end) returns a new sub-array without modifying the original. splice(start, deleteCount, ...items) modifies the original in-place and returns the removed elements. Confusing them is one of the most common array bugs.

⚠️

Many devs think Array(5) creates [0, 0, 0, 0, 0] — but actually Array(5) creates a sparse array with 5 empty slots and no actual elements. Methods like map and filter skip these holes. Use Array.from({ length: 5 }, () => 0) or new Array(5).fill(0) to create an array of actual zeros.

⚠️

Many devs think they can safely modify array state in React with push, splice, or sort — but actually these methods mutate the original array reference. React uses reference comparison for state change detection. Mutating and calling setState with the same reference tells React nothing changed, so it skips the re-render. Always create a new array: [...arr, newItem] or arr.filter().

⚠️

Many devs think forEach is equivalent to map for building new arrays — but actually forEach always returns undefined and is only for side effects. Using forEach with an external push is a code smell. Use map when you need a transformed array — it's cleaner, more declarative, and signals intent.

⚠️

Many devs think includes uses strict equality — but actually Array.prototype.includes uses the SameValueZero algorithm which treats NaN as equal to NaN. This means [NaN].includes(NaN) is true, unlike [NaN].indexOf(NaN) which returns -1. includes is the correct method for checking membership in arrays that might contain NaN.

Where You'll See This in Real Code

React's immutable state updates are entirely built on non-mutating array methods — every Redux reducer, useState updater, and useReducer case uses spread, filter, map, and concat instead of push/splice/sort. The entire React ecosystem is built on the principle that if you need to modify state, you return a new array, which is why knowing which array methods mutate is not academic but a daily practical requirement.

Virtual DOM diffing algorithms in React, Preact, and Vue use array indices as hints for reconciliation — providing key props on list items helps the diff algorithm match old and new arrays efficiently. Understanding that arrays are ordered indexed collections (unlike Sets) is why the key prop exists and why using array index as key causes bugs when items reorder.

JavaScript's typed arrays (Int32Array, Float64Array, Uint8Array) are fixed-length, fixed-type arrays that map directly to memory buffers — used in WebGL, WebAssembly, audio processing, and binary data manipulation. They share most array method names but have different performance characteristics (no dynamic resizing, cache-friendly memory layout).

Lodash's chunk, zip, unzip, groupBy, and intersection utilities exist because the native Array API lacks them — chunk([1,2,3,4], 2) produces [[1,2],[3,4]], which is impossible with a single native method. Understanding the native array API thoroughly makes you faster at recognizing when a utility library genuinely helps versus when a simple reduce() or flatMap() solves it natively.

The Array.from(document.querySelectorAll()) pattern is required because DOM NodeLists are array-like objects (they have length and numeric indices) but are not real arrays. They lack map, filter, and reduce. Array.from() converts any array-like or iterable into a true array, which is why it's the standard method for converting DOM collections to workable arrays.

ES2023's toSorted(), toReversed(), and with() methods were added specifically because the React and functional programming communities had been writing [...arr].sort() for years just to avoid mutating the original. The new methods signal that non-mutating operations are now a first-class concern in the language specification itself.

Interview Cheat Sheet

  • Mutating: push, pop, shift, unshift, splice, sort, reverse, fill — modify original
  • Non-mutating: map, filter, reduce, slice, concat, flat, flatMap, find, findIndex — return new
  • ES2023 non-mutating: toSorted, toReversed, toSpliced, with — explicit copies
  • sort() default: lexicographic (string) — always pass (a,b)=>a-b for numbers
  • splice vs slice: splice mutates + removes; slice copies a portion non-mutating
  • Array(5): sparse array with holes — use Array.from({length:5},()=>0) or fill(0)
  • Array.from(): convert any iterable/array-like to real array; accepts mapping function
  • includes: uses SameValueZero — handles NaN correctly; indexOf uses ===
  • flatMap: map then flat(1) in one pass — cleaner than chaining
  • React rule: never mutate state arrays — always return new array
💡

How to Answer in an Interview

  • 1.Mutating vs non-mutating is the most practical array question — list the mutating ones by name
  • 2.The sort() without comparator gotcha is in every output quiz — know the string-sort behavior
  • 3.splice vs slice distinction is asked constantly — give the one-line each way memory trick
  • 4.Demonstrating React's immutability requirement connects array knowledge to real framework work
  • 5.Array.from({length: N}, (_, i) => i) as an idiom for generating sequences shows fluency
📖 Deep Dive Articles
map() vs forEach() in JavaScript: Which One to Use and Why It Matters7 min readTop 50 JavaScript Interview Questions (With Deep Answers)18 min readJavaScript Performance Optimization: What Actually Makes Code Fast12 min read

Practice Questions

3 questions
#01

Async function in forEach

🔴 HardAsync BugsDebug
#02

When would you use map vs forEach vs reduce vs filter?

🟢 EasyArrays PRO💡 map=transform, filter=subset, reduce=accumulate, forEach=side effects
#03

Object mutation in array map

🟡 MediumFix the CodeDebug

Related Topics

JavaScript Immutability Interview Questions
Intermediate·3–5 Qs
JavaScript Destructuring Interview Questions
Beginner·4–6 Qs
JavaScript Higher-Order Functions Interview Questions
Intermediate·5–8 Qs
🎯

Can you answer these under pressure?

Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.

Practice Free →Try Output Quiz