Polyfills
What are Polyfills?
Polyfills are code snippets that provide modern functionality to older browsers that don't support it natively. They "fill in" the gaps in browser support.
Try Creating Polyfills
Code Editor
Console Output
Click "Run" to execute your code...
Example 1: Array Methods Polyfills
// Array.prototype.map() polyfill
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
if (this == null) {
throw new TypeError('Array.prototype.map called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
const arr = Object(this);
const len = arr.length >>> 0;
const result = new Array(len);
for (let i = 0; i < len; i++) {
if (i in arr) {
result[i] = callback.call(thisArg, arr[i], i, arr);
}
}
return result;
};
}
// Array.prototype.filter() polyfill
if (!Array.prototype.filter) {
Array.prototype.filter = function(callback, thisArg) {
if (this == null) {
throw new TypeError();
}
if (typeof callback !== 'function') {
throw new TypeError();
}
const arr = Object(this);
const len = arr.length >>> 0;
const result = [];
for (let i = 0; i < len; i++) {
if (i in arr) {
const val = arr[i];
if (callback.call(thisArg, val, i, arr)) {
result.push(val);
}
}
}
return result;
};
}
// Array.prototype.reduce() polyfill
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback, initialValue) {
if (this == null) {
throw new TypeError();
}
if (typeof callback !== 'function') {
throw new TypeError();
}
const arr = Object(this);
const len = arr.length >>> 0;
let accumulator, startIndex;
if (arguments.length >= 2) {
accumulator = initialValue;
startIndex = 0;
} else {
startIndex = 0;
while (startIndex < len && !(startIndex in arr)) {
startIndex++;
}
if (startIndex >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
accumulator = arr[startIndex++];
}
for (let i = startIndex; i < len; i++) {
if (i in arr) {
accumulator = callback(accumulator, arr[i], i, arr);
}
}
return accumulator;
};
}
// Array.prototype.find() polyfill
if (!Array.prototype.find) {
Array.prototype.find = function(callback, thisArg) {
if (this == null) {
throw new TypeError();
}
if (typeof callback !== 'function') {
throw new TypeError();
}
const arr = Object(this);
const len = arr.length >>> 0;
for (let i = 0; i < len; i++) {
if (i in arr) {
const val = arr[i];
if (callback.call(thisArg, val, i, arr)) {
return val;
}
}
}
return undefined;
};
}Example 2: Promise Polyfill (Simplified)
// Simplified Promise polyfill
if (typeof Promise === 'undefined') {
window.Promise = function(executor) {
const self = this;
self.state = 'pending';
self.value = undefined;
self.callbacks = [];
function resolve(value) {
if (self.state !== 'pending') return;
self.state = 'fulfilled';
self.value = value;
setTimeout(() => {
self.callbacks.forEach(callback => {
if (callback.onFulfilled) {
callback.onFulfilled(value);
}
});
}, 0);
}
function reject(reason) {
if (self.state !== 'pending') return;
self.state = 'rejected';
self.value = reason;
setTimeout(() => {
self.callbacks.forEach(callback => {
if (callback.onRejected) {
callback.onRejected(reason);
}
});
}, 0);
}
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
};
Promise.prototype.then = function(onFulfilled, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
function handle() {
if (self.state === 'fulfilled') {
if (typeof onFulfilled === 'function') {
try {
const result = onFulfilled(self.value);
resolve(result);
} catch (error) {
reject(error);
}
} else {
resolve(self.value);
}
} else if (self.state === 'rejected') {
if (typeof onRejected === 'function') {
try {
const result = onRejected(self.value);
resolve(result);
} catch (error) {
reject(error);
}
} else {
reject(self.value);
}
}
}
if (self.state === 'pending') {
self.callbacks.push({ onFulfilled, onRejected });
} else {
setTimeout(handle, 0);
}
});
};
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
}Example 3: Object Methods Polyfills
// Object.assign() polyfill
if (typeof Object.assign !== 'function') {
Object.assign = function(target) {
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
const to = Object(target);
for (let i = 1; i < arguments.length; i++) {
const nextSource = arguments[i];
if (nextSource != null) {
for (const key in nextSource) {
if (Object.prototype.hasOwnProperty.call(nextSource, key)) {
to[key] = nextSource[key];
}
}
}
}
return to;
};
}
// Object.keys() polyfill
if (!Object.keys) {
Object.keys = function(obj) {
if (obj !== Object(obj)) {
throw new TypeError('Object.keys called on non-object');
}
const keys = [];
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
keys.push(key);
}
}
return keys;
};
}
// Object.create() polyfill
if (typeof Object.create !== 'function') {
Object.create = function(proto, propertiesObject) {
if (typeof proto !== 'object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object or null');
}
function F() {}
F.prototype = proto;
const obj = new F();
if (propertiesObject !== undefined) {
Object.defineProperties(obj, propertiesObject);
}
return obj;
};
}
// Object.entries() polyfill
if (!Object.entries) {
Object.entries = function(obj) {
const entries = [];
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
entries.push([key, obj[key]]);
}
}
return entries;
};
}
// Object.values() polyfill
if (!Object.values) {
Object.values = function(obj) {
const values = [];
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
values.push(obj[key]);
}
}
return values;
};
}Example 4: Function Methods Polyfills
// Function.prototype.bind() polyfill
if (!Function.prototype.bind) {
Function.prototype.bind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Function.prototype.bind called on non-function');
}
const fn = this;
const args = Array.prototype.slice.call(arguments, 1);
return function() {
const allArgs = args.concat(Array.prototype.slice.call(arguments));
return fn.apply(context, allArgs);
};
};
}
// Function.prototype.call() polyfill
if (!Function.prototype.call) {
Function.prototype.call = function(context) {
context = context || window;
context.__fn__ = this;
const args = [];
for (let i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']');
}
const result = eval('context.__fn__(' + args + ')');
delete context.__fn__;
return result;
};
}
// Function.prototype.apply() polyfill
if (!Function.prototype.apply) {
Function.prototype.apply = function(context, arr) {
context = context || window;
context.__fn__ = this;
let result;
if (!arr) {
result = context.__fn__();
} else {
const args = [];
for (let i = 0; i < arr.length; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.__fn__(' + args + ')');
}
delete context.__fn__;
return result;
};
}Example 5: String and Modern Methods Polyfills
// String.prototype.includes() polyfill
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
}
return this.indexOf(search, start) !== -1;
};
}
// String.prototype.startsWith() polyfill
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(search, pos) {
pos = !pos || pos < 0 ? 0 : +pos;
return this.substring(pos, pos + search.length) === search;
};
}
// String.prototype.endsWith() polyfill
if (!String.prototype.endsWith) {
String.prototype.endsWith = function(search, this_len) {
if (this_len === undefined || this_len > this.length) {
this_len = this.length;
}
return this.substring(this_len - search.length, this_len) === search;
};
}
// Array.from() polyfill
if (!Array.from) {
Array.from = function(arrayLike, mapFn, thisArg) {
const items = Object(arrayLike);
const len = items.length >>> 0;
const result = new Array(len);
for (let i = 0; i < len; i++) {
if (i in items) {
result[i] = mapFn ? mapFn.call(thisArg, items[i], i) : items[i];
}
}
return result;
};
}
// Array.prototype.includes() polyfill
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError();
}
const arr = Object(this);
const len = arr.length >>> 0;
if (len === 0) {
return false;
}
const n = fromIndex | 0;
let k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while (k < len) {
if (arr[k] === searchElement ||
(searchElement !== searchElement && arr[k] !== arr[k])) {
return true;
}
k++;
}
return false;
};
}
// Usage example
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
const str = 'Hello World';
console.log(str.includes('World')); // true
console.log(str.startsWith('Hello')); // true
console.log(str.endsWith('World')); // trueKey Points
- Polyfills provide modern features to older browsers
- Always check if feature exists before adding polyfill
- Use feature detection, not browser detection
- Consider using polyfill services like polyfill.io
- Bundle only needed polyfills to reduce file size
- Babel can automatically add necessary polyfills
- Test polyfills thoroughly for edge cases