Q2: Implement a polyfill for Array.prototype.map().
Answer
The map() method creates a new array by applying a callback to each existing element of the original array. It does not mutate the original array.
A good polyfill should support the callback arguments value, index, and array, an optional thisArg, and sparse arrays.
Array.prototype.myMap = function (callback, thisArg) {
if (this == null) {
throw new TypeError("Array.prototype.myMap called on null or undefined");
}
if (typeof callback !== "function") {
throw new TypeError("Callback must be a function");
}
const array = Object(this);
const length = array.length >>> 0;
const result = new Array(length);
for (let i = 0; i < length; i++) {
if (i in array) {
result[i] = callback.call(thisArg, array[i], i, array);
}
}
return result;
};
console.log([1, 2, 3].myMap(n => n * 2));
// [2, 4, 6]
How it works
- Validate the receiver and callback.
- Convert the receiver to an object and capture its length.
- Create a result array with the same length.
- Visit only indexes that exist in the source array.
- Store the callback result at the corresponding index.
- Return the new array.
The i in array check preserves holes in sparse arrays. The unsigned right shift used above is a common interview simplification for obtaining a 32-bit unsigned length; it is not fully specification-compliant for every possible array-like object. A production-quality implementation should use LengthOfArrayLike semantics.
Map polyfill usage
const numbers = [1, 2, 3, 4];
const doubled = numbers.myMap((value, index, array) => {
console.log(index, array === numbers);
return value * 2;
});
console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4]💡 The callback receives the current value, index, and original array. The returned array contains transformed values without modifying the original array.
Key Takeaways
- Map returns a new array and preserves the source array.
- A robust implementation handles sparse arrays, callback validation, and thisArg.