Build: Array Polyfills (map/filter/reduce)
Introduction
Array polyfills are a direct test of JavaScript fundamentals: this binding, callback signatures, sparse arrays, optional thisArg, accumulator initialization, and prototype extension safety.
The implementation below mirrors the important behavior of map, filter, and reduce without relying on native equivalents.
Why This Matters
These methods are everywhere in production code, and polyfill questions reveal whether you understand the specification-level details behind familiar APIs. The edge cases are what interviewers care about: holes, missing initial values, and callback context.
Theory
Shared mechanics
All three methods convert this to an object, read a length snapshot, validate the callback, and skip holes with if (index in array). map preserves length and holes. filter returns a dense array of values that pass the predicate. reduce collapses values into one accumulator.
Callback signatures
map and filter call callback(value, index, array) and optionally bind thisArg. reduce calls callback(accumulator, value, index, array) and does not use thisArg.
Reduce initialization
If an initial value is provided, reduction starts there. If not, the first present array element becomes the accumulator. Calling reduce on an empty array with no initial value must throw a TypeError.
Visual Diagrams
Array method call | v validate callback | v snapshot length | v iterate present indexes only | +--> map: write same index +--> filter: push passing values +--> reduce: update accumulator
Sparse-array handling is the detail that many quick implementations miss.
Code Examples
Complete myMap, myFilter, and myReduce
The properties are defined as non-enumerable to avoid surprising for...in loops.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1Object.defineProperty(Array.prototype, 'myMap', {2 value: function (callback) {3 var array = Object(this);4 var result = new Array(array.length >>> 0);5 6 for (var index = 0; index < result.length; index += 1) {7 if (index in array) {8 result[index] = callback(array[index], index, array);9 }10 }11 12 return result;13 },14 writable: true,15 configurable: true16});17 18var sparse = [1, , 3];19var mapped = sparse.myMap(function (value, index) {20 return value + ':' + index;21});22console.log(mapped.length);23console.log(mapped.hasOwnProperty(1));24console.log(mapped[2]);Coding Exercises
Implement map, filter, and reduce polyfills
MediumAdd myMap, myFilter, and myReduce to Array.prototype.
Requirements:
- Throw
TypeErrorif called onnullorundefined. - Throw
TypeErrorif callback is not a function. - Use the correct callback signatures.
- Support
thisArgfor map and filter. - Skip holes in sparse arrays.
myMappreserves length and holes.myFilterreturns a dense array.myReducesupports optional initial value and throws on empty arrays without one.- Define properties as writable and configurable.
Constraints:
- Do not call native
map,filter, orreduceinside the implementations.
Interview Questions
1Why check `index in array` instead of `array[index] !== undefined`?
A sparse hole and an explicit undefined value are different. Native array methods skip holes but visit explicit undefined. index in array correctly detects whether the property exists.
2What happens when `reduce` is called on an empty array without an initial value?
It throws a TypeError because there is no first present element to use as the accumulator.
Quiz
1. Which method should preserve holes in the returned array?
Summary
- Array polyfills must validate `this` and callback inputs.
- `map` and `filter` use `(value, index, array)` and optional `thisArg`.
- `reduce` uses `(accumulator, value, index, array)` and has special initial-value rules.
- Use `index in array` to handle sparse arrays correctly.
Cheat Sheet
Array polyfill checklist
if (this == null) throw TypeError.if (typeof callback !== "function") throw TypeError.array = Object(this),length = array.length >>> 0.- Skip holes with
index in array. map: same length, callback with thisArg.filter: push passing values, dense result.reduce: initialize accumulator carefully, throw on empty without initial value.- Use
Object.defineProperty.