Implement map(), filter() & reduce() from Scratch

These three polyfills appear in almost every frontend interview. Build each one from scratch — handling the callback signature, thisArg, sparse arrays, and the reduce initialValue edge case.

12 min read
JavaScript
Interview
Implementation
Arrays

TABLE OF CONTENTS

map, filter, and reduce appear in nearly every frontend interview. The question is rarely "do you know how to use them" — it's "implement them from scratch." Here's how to build polyfills that handle every edge case an interviewer will throw at you.


What are map(), filter(), and reduce()?

These are the three foundational higher-order array methods. Each takes a callback and iterates over the array — what differs is what they return and when the callback is invoked.

  • map(callback) — transforms each element and returns a new array of the same length. Every element goes through the callback; the result array mirrors the input structure. Use it when you want to change shape or type: users.map(u => u.name).
  • filter(callback) — returns a new array containing only elements where the callback returned a truthy value. The result array is the same shape but possibly shorter. Use it to remove unwanted items: numbers.filter(n => n > 0).
  • reduce(callback, initialValue)accumulates the array into a single value. It's the most general of the three — both map and filter can be implemented with reduce. The callback receives an accumulator and each element, and the accumulator carries state across iterations. Use it for sums, grouping, flattening, or any operation that collapses an array.

What makes these three interview staples is that they test array iteration mechanics: sparse array holes, the optional thisArg parameter, and the fact that the callback receives (element, index, array). Building them from scratch proves you understand iteration protocols, not just the API surface.


The Problem

"Implement Array.prototype.myMap, myFilter, and myReduce from scratch. Each must match the native method's behavior: callback signature, thisArg, and sparse array handling."


Thought Process

All three follow the same skeleton:

1. Check that `this` is a valid array (or array-like)
2. Check that the callback is callable
3. Iterate over the array (skipping holes in sparse arrays)
4. Call the callback with (element, index, array)
5. Build and return the result

The differences are in step 5:

  • map: return a new array of the same length with transformed values
  • filter: return a new array with only elements that pass the test
  • reduce: accumulate into a single value

Step 1 — myMap

Loading editor...

The i in arr check is crucial. In a sparse array like [1, , 3], index 1 doesn't exist. arr[1] would be undefined, but the native map skips it entirely. Using i in arr correctly detects holes vs. actual undefined values.


Step 2 — myFilter

Same structure, but we push matching elements instead of transforming every element:

Loading editor...


Step 3 — myReduce

reduce has one unique edge case: the initialValue parameter. If it's not provided, the first element of the array becomes the initial accumulator, and iteration starts from index 1. If the array is empty and no initialValue is given, reduce throws a TypeError.

Loading editor...


Step 4 — Edge Cases the Interviewer Will Test

Sparse arrays: [1, , 3] — all three methods must skip the hole, not treat it as undefined.

thisArg with myReduce: The native reduce passes undefined as the this for the callback. Our implementation does the same with callback.call(undefined, ...).

Callback that mutates the array: The native methods iterate based on the array's length at the time they're called, but they do read current values. If the callback pushes to the array, map and filter won't iterate the new elements. If it removes elements, the length doesn't shrink mid-iteration.

No callback provided: All three should throw a TypeError.


Step 5 — Full Solution

Loading editor...


What Interviewers Are Testing

  • Callback signature — you know it's (element, index, array), not just (element)
  • thisArg — you pass it to callback.call(thisArg, ...) so the callback's this is correct
  • Sparse array handlingi in arr vs checking arr[i] !== undefined
  • reduce initialValue logic — the two-path initialization: with vs without initial value
  • Type checking — throwing TypeError when the callback isn't a function

Complexity

MethodTimeSpace
myMapO(n)O(n)
myFilterO(n)O(n)
myReduceO(n)O(1)

Interview Tips

  • Write myMap first and talk through it — it establishes the pattern. Then say "myFilter is almost the same but with a condition check" and write it quickly.
  • Don't rush myReduce — the initialValue logic is what interviewers want to see. Say "there are two cases for the accumulator initialization" before you start coding.
  • Mention i in arr out loud — "I'm using i in arr rather than comparing to undefined because sparse arrays have actual holes, and the callback should not be called for them."
  • Know the TypeError message — "Reduce of empty array with no initial value" is the exact wording. Reciting the correct error shows deep familiarity.

Related Questions


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI