All three polyfills follow the same structure:
i in this
to handle arrays with missing indices
callback.call(thisArg, ...)
to set the
this
context
(element, index, array)
(accumulator, element, index, array)
Understanding polyfills helps you:
Map creates a NEW array by transforming each element using a callback function. It's like having a factory that processes each item and outputs a modified version.
// Our custom map polyfill
Array.prototype.myMap = function(callback, thisArg) {
// Check if callback is a function
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// Create new array to store results
const result = [];
// Loop through each element
for (let i = 0; i < this.length; i++) {
// Check if index exists (sparse arrays)
if (i in this) {
// Call callback with: element, index, array
result[i] = callback.call(thisArg, this[i], i, this);
}
}
return result;
};
Filter creates a NEW array containing only elements that pass a test. Think of it as a bouncer that only lets certain items through based on your criteria.
// Our custom filter polyfill
Array.prototype.myFilter = function(callback, thisArg) {
// Check if callback is a function
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// Create new array for filtered results
const result = [];
// Loop through each element
for (let i = 0; i < this.length; i++) {
// Check if index exists
if (i in this) {
// Test element with callback
if (callback.call(thisArg, this[i], i, this)) {
// Only add if test passes
result.push(this[i]);
}
}
}
return result;
};
Reduce takes an array and "reduces" it to a single value by applying a function that combines elements. Like a snowball rolling downhill, gathering more snow (data) as it goes.
// Our custom reduce polyfill
Array.prototype.myReduce = function(callback, initialValue) {
// Check if callback is a function
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// Handle empty arrays
if (this.length === 0 && arguments.length < 2) {
throw new TypeError('Reduce of empty array with no initial value');
}
let accumulator;
let startIndex = 0;
// Set up initial values
if (arguments.length >= 2) {
accumulator = initialValue;
} else {
// Find first valid element as initial value
while (startIndex < this.length && !(startIndex in this)) {
startIndex++;
}
accumulator = this[startIndex];
startIndex++;
}
// Process each element
for (let i = startIndex; i < this.length; i++) {
if (i in this) {
// Call callback with: accumulator, element, index, array
accumulator = callback(accumulator, this[i], i, this);
}
}
return accumulator;
};
Modify the polyfills below and test your changes instantly!
Click the buttons to see our polyfills in action and compare with native methods!