JavaScript (ES2026) Module 6
Arrays and array methods interview questions
Interview questions on arrays and array methods: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between a hole and undefined in a JavaScript array?
-
Fresher
What is the difference between slice() and splice() in JavaScript?
-
Fresher
What is the difference between includes() and indexOf() on a JavaScript array?
Answered in the lesson Searching: includes, indexOf, find, some and every
-
Fresher
What is the difference between map() and forEach() in JavaScript?
Answered in the lesson Transforming arrays with map, filter and forEach
-
Fresher
What does reduce() do in JavaScript, and why should you pass an initial value?
-
Fresher
What does it mean that sort() is stable, and when do you rely on it?
-
Fresher
What is the difference between splice() and toSpliced()?
Answered in the lesson Copying array methods: toSorted, toSpliced, with
-
Fresher
What is the difference between Array(3), Array.of(3) and Array.from({ length: 3 })?
Answered in the lesson flat, flatMap, Array.from and array-likes
-
Fresher
What is the difference between Object.groupBy and Map.groupBy?
Answered in the lesson Grouping data with Object.groupBy and Map.groupBy
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A class register stores marks with marks[rollNumber] = score, and the roll numbers are 101, 205 and 340. The report prints "Class size: 341", the average is wrong, and JSON.stringify(marks) is mostly null. Explain what happened to the array, and what you would store instead.
- What it tests
- How length follows the highest index, how holes behave in loops, methods and JSON, and choosing an object or a Map when the keys are sparse numbers.
- First step
- Writing marks[340] makes length 341, one more than the highest index, and every index nobody wrote is a hole. length counts slots, not students, so code that divides by length, or loops from 0 to length - 1, treats 338 empty slots as students.
- Follow-ups
-
- Which loops and methods see the holes, and which skip them?
- Why does JSON.stringify() write null for the missing roll numbers?
- Map, plain object or an array of records: which would you pick, and why?
From the lesson Arrays: creating, reading and length
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A Node.js worker keeps pending jobs in an array: push() to add, shift() to take the next. After an outage 80,000 jobs pile up, and draining them keeps a CPU core busy for about a second, while a test queue of 10,000 drained in a millisecond. Explain the difference and design a queue that stays fast.
- What it tests
- The cost of shift() on long arrays, reading a measurement that jumps instead of growing smoothly, and designing a queue whose dequeue costs O(1) on average.
- First step
- shift() moves every remaining item down one index, so draining n items moves about n²/2 of them: 3.2 billion for 80,000. V8 avoids the copy for small arrays by moving the start of their storage, which is why 10,000 jobs looked free, but it cannot do that once the storage outgrows 128 KiB.
- Follow-ups
-
- Why did the queue of 10,000 not show the problem?
- How do you stop a head-index queue from holding on to memory?
- When is shift() perfectly fine to use?
From the lesson Adding and removing items
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A helper reads function removeItem(cart, index) { return cart.splice(index, 1); }, and the screen calls setCart(removeItem(cart, i)). Removing a product leaves the cart showing only that product, and another screen that shares the same cart array loses items too. Explain both bugs and fix the helper.
- What it tests
- What splice() returns, that it changes the array it is called on, how a change spreads through shared references, and writing the update with toSpliced() or filter().
- First step
- splice() changes cart itself and returns an array of the removed items. So the new state is the one removed product, and because the original array was changed in place, every other holder of that same array sees the product gone as well.
- Follow-ups
-
- Write the helper so that it neither changes the cart nor returns the wrong thing.
- Why might a user interface library skip redrawing after cart.splice()?
- When is changing the array in place the right choice?
From the lesson Adding and removing items
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A release script runs const ok = checks.every((c) => c.passed) before deploying. One night the CI configuration failed to load, checks came back as an empty array, and a broken build went to production. Explain why the script said yes, and how you would make it fail closed.
- What it tests
- every() returning true for an empty array, some() returning false, and designing checks that treat missing evidence as a failure rather than a success.
- First step
- every() returns false only when it finds an item that fails. An empty array has no items, so it returns true without calling the function: the script let through a release with no checks at all. some() follows the mirror rule and returns false for an empty array.
- Follow-ups
-
- How would you write the check so that an empty or incomplete list fails?
- Where else does an empty array quietly mean yes?
- How would you test the release script for this case?
From the lesson Searching: includes, indexOf, find, some and every
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A sign-up endpoint checks each new username against 300,000 reserved and taken names with reserved.includes(name.toLowerCase()). It is fast in tests but slow under load. Estimate the cost, propose a better structure with numbers, and say what changes about how names are compared.
- What it tests
- The cost of a linear search, Set lookups and their one-off build cost, SameValueZero comparison, and normalising keys the same way when storing and when checking them.
- First step
- includes() compares the name with the stored names one at a time, so a name that is not taken costs 300,000 string comparisons. At 1,000 sign-ups a second that is 300 million comparisons a second. Build a Set once at start-up and call has(), which finds a name without scanning.
- Follow-ups
-
- What does building the Set cost, and when do you rebuild it?
- Does a Set compare strings the same way as includes()?
- What about names that differ only in letter case or in Unicode form?
From the lesson Searching: includes, indexOf, find, some and every
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
function allValid(rows) { rows.forEach((r) => { if (!r.email) return false; }); return true; } should reject an upload with any row that has no email, but it accepts every file. Explain why, and give two correct versions, saying which one you would ship.
- What it tests
- That a return inside a forEach() callback ends only that call, that forEach() ignores return values and cannot stop early, and choosing every() or a loop instead.
- First step
- The return false belongs to the arrow function, not to allValid(). forEach() calls the arrow once per row, ignores what it returns and always runs to the end, so allValid() reaches its own return true whatever the rows contain.
- Follow-ups
-
- Which version stops at the first bad row, and why does that matter for a file of 100,000 rows?
- How would you report which rows are invalid, not just whether all of them are valid?
- What changes if each check has to await a database lookup?
From the lesson Transforming arrays with map, filter and forEach
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A nightly report runs orders.filter(isPaid).map(toRupees).filter(isLarge).length on 5 million orders, and the Node.js process now runs close to its memory limit. Explain where the memory goes, with rough numbers, and rewrite the code, saying what each rewrite trades.
- What it tests
- That each array method builds a whole new array, estimating memory from the item counts, and choosing between a loop, reduce() and iterator helpers with measured trade-offs.
- First step
- Each step builds a complete array before the next one starts. If 90 % of orders are paid and most of those are large, the chain builds arrays of about 4.5, 4.5 and 3.6 million slots, some 12.6 million slots of 8 bytes: roughly 100 MB of arrays that exist only to be counted.
- Follow-ups
-
- Why not just raise --max-old-space-size?
- Are iterator helpers faster than the chain in Node.js 24?
- When is the chain still the better code?
From the lesson Transforming arrays with map, filter and forEach
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A helper builds a lookup with rows.reduce((acc, r) => ({ ...acc, [r.id]: r }), {}). It takes about a tenth of a second for 1,000 rows, but a customer with 20,000 rows reports the page freezing for minutes. Explain the growth with numbers, fix it, and say when the spread version is acceptable.
- What it tests
- Spotting quadratic copying in an immutable-looking reduce(), estimating its cost from the number of rows, and fixing it with a local accumulator or a Map.
- First step
- Count the copies. The spread on row k copies the k - 1 properties already in the accumulator, so n rows copy n(n - 1)/2 properties: about 500,000 for 1,000 rows and 200 million for 20,000, 400 times as many for 20 times the rows.
- Follow-ups
-
- Is changing the accumulator safe, when the team prefers immutable code?
- Map, Object.fromEntries() or a plain object: which would you return?
- How would you find this kind of hot spot in production?
From the lesson reduce in depth
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
const total = expenses.reduce((sum, e) => sum + e.amountPaise); shows "[object Object]120000" on the monthly report, and the same line crashes with a TypeError for a month with no expenses. Explain both failures, the fix, and one more case in which the missing initial value hides a bug.
- What it tests
- How reduce() starts without an initial value, the empty-array TypeError, and how adding a number to an object turns both into text.
- First step
- Without an initial value, reduce() takes the first expense object as the starting sum and begins with the second item, so the first addition is an object plus a number: the object becomes the text "[object Object]" and the digits are joined to it. With no expenses there is no first item, so the language requires a TypeError.
- Follow-ups
-
- What does the same line give for a month with exactly one expense?
- Would TypeScript have caught it?
- How would you test the report so that the bug cannot come back?
From the lesson reduce in depth
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A leaderboard is sorted with players.sort((a, b) => a.points < b.points). A unit test with three players passed in one JavaScript engine, yet in Node.js and Chrome the list comes back in its original order. Explain why, fix it, and say how you would keep this kind of comparator bug out of the code base.
- What it tests
- What a comparator must return, how sort() converts a boolean, consistent comparators and implementation-defined order, why an engine's algorithm hides the bug, and catching it with types and tests.
- First step
- Write down what the comparator returns: true or false, which sort() converts to 1 or 0, so it never says that a comes first. V8 sorts with Timsort, which starts by looking for runs that are already in order; with no negative answer the whole array looks like one run, and nothing moves.
- Follow-ups
-
- Why did the test with three players pass in the other engine?
- How do you sort by points and then by name?
- Which tools would have caught the bug before review?
From the lesson Sorting arrays correctly
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
An admin page exports 200,000 customer names, written in English and in Hindi, sorted for the reader's language with (a, b) => new Intl.Collator(userLocale, { numeric: true }).compare(a.name, b.name). The export takes about 20 seconds. Explain the cost, fix it, and say how you would choose and test the order.
- What it tests
- Counting comparator calls, the cost of creating a collator, reusing one, choosing the locale from the reader, and testing an order that depends on the language.
- First step
- Count the comparator calls: sorting 200,000 names calls the comparator well over a million times, up to about n log2 n, some 3.5 million, for random data. Each call here creates a new collator, which resolves the locale and the options again, so setup meant to happen once happens millions of times.
- Follow-ups
-
- Is localeCompare() any better than a collator?
- Names in Hindi and English are mixed. Which order is right?
- How do you test that the order is correct?
From the lesson Sorting arrays correctly
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An import screen applies one fix per row with rows = rows.with(i, fixRow(rows[i])) in a loop, to keep state immutable. With 50,000 rows the tab freezes for seconds, and a teammate concludes that the copying methods are too slow to use. Explain the cost with numbers, rewrite the update, and say when with() is the right tool.
- What it tests
- Seeing that each copy costs O(n), turning the loop's total into n² with numbers, rewriting it with one map() or one private copy, and keeping state immutable where other code can see it.
- First step
- Count what each call writes: with() builds a new array of all 50,000 rows, and the loop calls it 50,000 times, so it writes 2.5 billion slots to change 50,000 values. The method is not slow; calling it once per row is.
- Follow-ups
-
- Is mutating a local copy still immutable code?
- What would you do if only 30 of the 50,000 rows change?
- How would you find this in a performance profile?
From the lesson Copying array methods: toSorted, toSpliced, with
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A settings page shows the user's saved addresses sorted with addresses.toSorted(byCity). When the user edits an address in the sorted view with sorted[i].city = 'Pune', the saved list changes too, and the undo button stops working. Explain why, and fix the edit so that the saved list stays as it was.
- What it tests
- That the copying methods make shallow copies, how item objects are shared between arrays, why a change through one array shows in the other, and editing by replacing an item with a new object.
- First step
- Check what toSorted() copied: the list of references. sorted[i] and the matching item of addresses are the same object, so assigning to sorted[i].city changes the one object that both arrays point to. Prove it with sorted[i] === addresses.find((a) => a.id === sorted[i].id).
- Follow-ups
-
- Would structuredClone() before sorting fix it, and at what cost?
- How does Object.freeze help catch this in development?
- How would the undo feature keep its history cheaply?
From the lesson Copying array methods: toSorted, toSpliced, with
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Write flatten(array, depth = 1) without using flat(), with the same results: holes skipped and only real arrays flattened. Then make it work for input nested 100,000 levels deep, where flat(Infinity) itself throws a RangeError in Node.js, and give the complexity of your version.
- What it tests
- Recursion and the stack limit, replacing calls with an explicit stack, keeping the order, depth counting, holes and array checks, and the O(n) cost of flattening.
- First step
- Write the recursive version first: for each index that exists, if the item is an array and the depth is above 0, recurse with depth - 1, otherwise push it. Every level of nesting adds a call frame, which is why very deep input overflows the stack, so then replace the calls with a stack of arrays and next indexes.
- Follow-ups
-
- How deep can flat(Infinity) go in Node.js 24?
- Why check Array.isArray instead of item.length?
- Could a generator make it lazy?
From the lesson flat, flatMap, Array.from and array-likes
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A page removes expired banners with const list = document.getElementsByClassName('expired'); for (let i = 0; i < list.length; i++) list[i].remove(); but half of the banners stay on the page. Explain exactly which ones stay and why, and give two correct ways to remove them all.
- What it tests
- Live and static collections, how removing items shifts the indexes of a live view, array-likes and snapshots with Array.from(), and querySelectorAll() returning a static NodeList.
- First step
- Trace the loop with ten banners. getElementsByClassName() returns a live HTMLCollection, so removing banner 0 moves banner 1 to index 0, and the loop's next index, 1, is banner 2. Every other banner is skipped, and the loop stops when i reaches the shrinking length.
- Follow-ups
-
- Would for…of over the live collection fix it?
- Is querySelectorAll() always the better choice?
- Which array methods can you use on these collections?
From the lesson flat, flatMap, Array.from and array-likes
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A shop's admin page groups orders by day with Map.groupBy(orders, (o) => o.placedAt), where placedAt is a Date, and 4,000 orders make 4,000 groups. After a fix that groups by o.placedAt.toISOString().slice(0, 10), shop owners in India report that orders placed just after midnight show up under the previous day. Explain both bugs and fix them.
- What it tests
- How a Map compares object keys, choosing value keys, toISOString() working in UTC, the +05:30 offset of India Standard Time, and computing a day key in a named time zone.
- First step
- Take the bugs one at a time. A Map compares keys by identity, and every Date is a separate object, so equal dates still make separate groups. Then note that toISOString() is always UTC, five and a half hours behind India, so anything placed before 05:30 there still carries the previous UTC date.
- Follow-ups
-
- Why not toLocaleDateString() as the key?
- The shop sells in several countries. What changes?
- Why a string key and not a Date for midnight?
From the lesson Grouping data with Object.groupBy and Map.groupBy
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A nightly report computes revenue per city with Object.groupBy(orders, (o) => o.city) and then sums each group. With 5 million orders the job's memory grows by tens of megabytes and the run slows down. Explain where the memory goes with an estimate, write a version that keeps only the totals, and say when grouping is still the right call.
- What it tests
- That groups hold a reference to every item, estimating memory per item, aggregating in one pass into a Map, and choosing between grouping and direct aggregation.
- First step
- Estimate what the groups hold: one array slot per order, about 8 bytes each in Node.js, so 5 million orders add some 40 MB of arrays on top of the orders themselves, all to be read once and thrown away. The report needs only one number per city.
- Follow-ups
-
- When is Object.groupBy then summing still the right code?
- What if the orders arrive as a stream, not an array?
- How would you prove where the memory goes?
From the lesson Grouping data with Object.groupBy and Map.groupBy
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
All JavaScript (ES2026) interview questions · The JavaScript (ES2026) track