if (!Array.prototype.map) { Array.prototype.map = function(callback, thisArg) { if (this == null) { throw new TypeError('this is null or not defined'); } if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } var O = Object(this); var len = O.length >>> 0; var A = new Array(len); var k = 0; while (k < len) { if (k in O) { A[k] = callback.call(thisArg, O[k], k, O); } k++; } return A; };}
Example: Array.prototype.find and findIndex polyfills
// Array.find polyfillif (!Array.prototype.find) { Array.prototype.find = function(predicate, thisArg) { if (this == null) throw new TypeError('this is null or not defined'); if (typeof predicate !== 'function') throw new TypeError('predicate must be a function'); var O = Object(this); var len = O.length >>> 0; for (var k = 0; k < len; k++) { if (k in O) { var kValue = O[k]; if (predicate.call(thisArg, kValue, k, O)) { return kValue; } } } return undefined; };}// Array.findIndex polyfillif (!Array.prototype.findIndex) { Array.prototype.findIndex = function(predicate, thisArg) { if (this == null) throw new TypeError('this is null or not defined'); if (typeof predicate !== 'function') throw new TypeError('predicate must be a function'); var O = Object(this); var len = O.length >>> 0; for (var k = 0; k < len; k++) { if (k in O && predicate.call(thisArg, O[k], k, O)) { return k; } } return -1; };}
if (!Array.prototype.includes) { Array.prototype.includes = function(searchElement, fromIndex) { if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); var len = O.length >>> 0; if (len === 0) return false; var n = fromIndex | 0; var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); // Handle NaN comparison (NaN === NaN should be true) while (k < len) { var currentElement = O[k]; if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement)) { return true; } k++; } return false; };}
if (!Object.assign) { Object.assign = function(target) { 'use strict'; if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { for (var nextKey in nextSource) { if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; };}
Example: Object.keys, values, and entries polyfills
// Object.keys polyfillif (!Object.keys) { Object.keys = function(obj) { if (obj !== Object(obj)) { throw new TypeError('Object.keys called on non-object'); } var keys = []; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { keys.push(key); } } return keys; };}// Object.values polyfillif (!Object.values) { Object.values = function(obj) { if (obj !== Object(obj)) { throw new TypeError('Object.values called on non-object'); } var values = []; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { values.push(obj[key]); } } return values; };}// Object.entries polyfillif (!Object.entries) { Object.entries = function(obj) { if (obj !== Object(obj)) { throw new TypeError('Object.entries called on non-object'); } var entries = []; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { entries.push([key, obj[key]]); } } return entries; };}// Object.fromEntries polyfillif (!Object.fromEntries) { Object.fromEntries = function(iterable) { var obj = {}; for (var pair of iterable) { if (Object(pair) !== pair) { throw new TypeError('iterable for fromEntries should yield objects'); } obj[pair[0]] = pair[1]; } return obj; };}
// String.prototype.padStartif (!String.prototype.padStart) { String.prototype.padStart = function(targetLength, padString) { targetLength = targetLength >> 0; padString = String(padString !== undefined ? padString : ' '); if (this.length > targetLength) { return String(this); } targetLength = targetLength - this.length; if (targetLength > padString.length) { padString += padString.repeat(targetLength / padString.length); } return padString.slice(0, targetLength) + String(this); };}// String.prototype.padEndif (!String.prototype.padEnd) { String.prototype.padEnd = function(targetLength, padString) { targetLength = targetLength >> 0; padString = String(padString !== undefined ? padString : ' '); if (this.length > targetLength) { return String(this); } targetLength = targetLength - this.length; if (targetLength > padString.length) { padString += padString.repeat(targetLength / padString.length); } return String(this) + padString.slice(0, targetLength); };}// String.prototype.repeat (needed for padStart/padEnd)if (!String.prototype.repeat) { String.prototype.repeat = function(count) { 'use strict'; if (this == null) throw new TypeError('can\'t convert ' + this + ' to object'); var str = '' + this; count = +count; if (count != count) count = 0; if (count < 0) throw new RangeError('repeat count must be non-negative'); if (count == Infinity) throw new RangeError('repeat count must be less than infinity'); count = Math.floor(count); if (str.length == 0 || count == 0) return ''; var maxCount = str.length * count; count = Math.floor(Math.log(count) / Math.log(2)); while (count) { str += str; count--; } str += str.substring(0, maxCount - str.length); return str; };}
4. Number Methods (isNaN, isFinite, parseInt, parseFloat)
Method
Syntax
Returns
Key Difference
Number.isNaN
Number.isNaN(value)
true only if value is NaN
Doesn't coerce - more reliable than global isNaN
Number.isFinite
Number.isFinite(value)
true if finite number
Doesn't coerce - stricter than global isFinite
Number.isInteger
Number.isInteger(value)
true if integer number
No decimal part
Number.isSafeInteger
Number.isSafeInteger(value)
true if safe integer
Between -(2^53-1) and 2^53-1
Number.parseInt
Number.parseInt(string, radix)
Integer parsed from string
Same as global parseInt
Number.parseFloat
Number.parseFloat(string)
Float parsed from string
Same as global parseFloat
Example: Number static method polyfills
// Number.isNaN - more reliable than global isNaNif (!Number.isNaN) { Number.isNaN = function(value) { // NaN is the only value that is not equal to itself return typeof value === 'number' && value !== value; };}// Number.isFinite - stricter than global isFiniteif (!Number.isFinite) { Number.isFinite = function(value) { return typeof value === 'number' && isFinite(value); };}// Number.isIntegerif (!Number.isInteger) { Number.isInteger = function(value) { return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; };}// Number.isSafeIntegerif (!Number.isSafeInteger) { Number.isSafeInteger = function(value) { return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER; };}// Number.parseInt and parseFloat (ES6 additions)if (!Number.parseInt) { Number.parseInt = parseInt;}if (!Number.parseFloat) { Number.parseFloat = parseFloat;}// Number constants polyfillsif (!Number.EPSILON) { Number.EPSILON = Math.pow(2, -52);}if (!Number.MAX_SAFE_INTEGER) { Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;}if (!Number.MIN_SAFE_INTEGER) { Number.MIN_SAFE_INTEGER = -(Math.pow(2, 53) - 1);}
Note:Number.isNaN() and Number.isFinite() don't coerce values to
numbers, unlike their global counterparts. Use them for stricter type checking: Number.isNaN('NaN')
returns false, while isNaN('NaN') returns true.
5. Symbol and Symbol Registry Polyfills
Feature
Syntax
Purpose
Limitations
Symbol()
Symbol(description)
Create unique symbol
Cannot be fully polyfilled (primitives)
Symbol.for()
Symbol.for(key)
Get/create global symbol
Registry can be emulated
Symbol.keyFor()
Symbol.keyFor(sym)
Get key for global symbol
Works with Symbol.for
Well-known Symbols
Symbol.iterator, etc
Standard protocol symbols
Partial support possible
Example: Basic Symbol polyfill (limited functionality)
// Basic Symbol polyfill (cannot create true primitives)if (typeof Symbol === 'undefined') { (function() { var symbolCounter = 0; var symbolRegistry = {}; // Symbol constructor window.Symbol = function Symbol(description) { if (this instanceof Symbol) { throw new TypeError('Symbol is not a constructor'); } var symbol = { __symbol__: true, __description__: description, __id__: symbolCounter++, toString: function() { return 'Symbol(' + (description || '') + ')'; }, valueOf: function() { return this; } }; return symbol; }; // Symbol.for - global symbol registry Symbol.for = function(key) { if (symbolRegistry[key]) { return symbolRegistry[key]; } var symbol = Symbol(key); symbolRegistry[key] = symbol; return symbol; }; // Symbol.keyFor Symbol.keyFor = function(sym) { for (var key in symbolRegistry) { if (symbolRegistry[key] === sym) { return key; } } return undefined; }; // Well-known symbols Symbol.iterator = Symbol('Symbol.iterator'); Symbol.toStringTag = Symbol('Symbol.toStringTag'); Symbol.hasInstance = Symbol('Symbol.hasInstance'); Symbol.toPrimitive = Symbol('Symbol.toPrimitive'); })();}// Usage examplevar sym1 = Symbol('description');var sym2 = Symbol.for('global');var sym3 = Symbol.for('global');console.log(sym2 === sym3); // trueconsole.log(Symbol.keyFor(sym2)); // 'global'
Warning: Symbols cannot be fully polyfilled in ES5 environments as they are primitive types.
Polyfills use objects, which means typeof polyfillSymbol returns 'object' instead of
'symbol'. Use with caution and test thoroughly.
6. Iterator and Generator Function Polyfills
Feature
Protocol
Method
Returns
Iterable
[Symbol.iterator]()
Returns iterator object
Object with next() method
Iterator
next()
Advances to next value
{value, done} object
Generator
function*
Creates iterator with yield
Cannot be fully polyfilled
for...of
Consumes iterables
Loops over iterable values
Requires transpilation
Example: Custom iterator implementation
// Add iterator to custom objectvar myIterable = { data: [1, 2, 3, 4, 5], [Symbol.iterator]: function() { var index = 0; var data = this.data; return { next: function() { if (index < data.length) { return { value: data[index++], done: false }; } else { return { done: true }; } } }; }};// Usage with for...of (requires transpilation or native support)// for (var value of myIterable) {// console.log(value); // 1, 2, 3, 4, 5// }// Manual iteration (works in ES5)var iterator = myIterable[Symbol.iterator]();var result = iterator.next();while (!result.done) { console.log(result.value); result = iterator.next();}// Add iterator to Array-like objectsfunction makeIterable(arrayLike) { arrayLike[Symbol.iterator] = function() { var index = 0; var self = this; return { next: function() { if (index < self.length) { return { value: self[index++], done: false }; } return { done: true }; } }; }; return arrayLike;}// Add iterator to String (if not supported)if (!String.prototype[Symbol.iterator]) { String.prototype[Symbol.iterator] = function() { var index = 0; var string = this; return { next: function() { if (index < string.length) { return { value: string[index++], done: false }; } return { done: true }; } }; };}
Note: Generator functions (function*) cannot be polyfilled and require
transpilation with tools like Babel. The regenerator-runtime package provides generator support for environments
without native support.
Key Takeaways - ECMAScript Features
Array methods: map, filter, find for ES5/ES6 compatibility
Object methods: Use Object.assign for merging, entries/values for iteration
String methods: includes, startsWith, endsWith for ES6 string operations
Number methods: Number.isNaN and isFinite provide strict type checking
Symbol polyfills: Limited - use objects but cannot replicate primitive
behavior
Iterators: Can be polyfilled; generators require transpilation