// Standard Polyfill Template(function() { 'use strict'; // Feature detection - exit if already exists if (Array.prototype.includes) { return; } // Polyfill implementation Array.prototype.includes = function(searchElement, fromIndex) { // Step 1: Type check - throw if this is null/undefined if (this == null) { throw new TypeError('Array.prototype.includes called on null or undefined'); } // Step 2: Convert this to object var O = Object(this); // Step 3: Get and convert length to unsigned 32-bit integer var len = parseInt(O.length) || 0; // Step 4: Handle edge cases if (len === 0) { return false; } // Step 5: Process fromIndex parameter var n = parseInt(fromIndex) || 0; var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); // Step 6: Main algorithm while (k < len) { var currentElement = O[k]; // Handle NaN comparison (NaN === NaN should be true) if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement)) { return true; } k++; } // Step 7: Return result return false; };})();
Note: Always wrap polyfills in an IIFE to avoid polluting global scope. Use strict mode to catch errors and ensure feature
detection runs first to avoid overwriting native implementations.
2. Prototype Extension Best Practices
Practice
Do This
Don't Do This
Reason
Check Existence
if (!proto.method)
Unconditional assignment
Preserve native implementation
Use defineProperty
Object.defineProperty()
proto.method = fn
Control enumerability and writability
Non-enumerable
enumerable: false
enumerable: true
Don't break for...in loops
Configurable
configurable: true
configurable: false
Allow future modifications
Test Context
if (this == null) throw
Assume this is valid
Match native error behavior
Handle Edge Cases
Check length, NaN, undefined
Assume happy path
Spec compliance and robustness
Example: Proper prototype extension with defineProperty
// Good: Using Object.definePropertyif (!Array.prototype.find) { Object.defineProperty(Array.prototype, 'find', { value: function(predicate) { 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; var thisArg = arguments[1]; 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; }, configurable: true, writable: true, enumerable: false // Critical: prevents for-in enumeration });}// Bad: Direct assignment (enumerable by default)// Array.prototype.find = function() { ... }; // DON'T DO THIS
Warning: Never extend prototypes of native objects without feature
detection. Always use Object.defineProperty with enumerable: false to avoid breaking existing code.
3. Static Method Polyfill Implementation
Type
Pattern
Check Method
Example
Object Static
Object.assign = function() {}
if (!Object.assign)
Object.keys, Object.values, Object.entries
Array Static
Array.from = function() {}
if (!Array.from)
Array.from, Array.of, Array.isArray
Number Static
Number.isNaN = function() {}
if (!Number.isNaN)
Number.isFinite, Number.parseInt
String Static
String.fromCodePoint = function() {}
if (!String.fromCodePoint)
String.raw, String.fromCodePoint
Math Static
Math.trunc = function() {}
if (!Math.trunc)
Math.sign, Math.trunc, Math.cbrt
Example: Static method polyfills
// Object.assign polyfillif (!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; };}// Array.from polyfillif (!Array.from) { Array.from = function(arrayLike, mapFn, thisArg) { var C = this; var items = Object(arrayLike); var len = items.length >>> 0; var A = typeof C === 'function' ? Object(new C(len)) : new Array(len); var k = 0; while (k < len) { var kValue = items[k]; if (mapFn) { A[k] = typeof thisArg === 'undefined' ? mapFn(kValue, k) : mapFn.call(thisArg, kValue, k); } else { A[k] = kValue; } k++; } A.length = len; return A; };}// Number.isNaN polyfill (more accurate than global isNaN)if (!Number.isNaN) { Number.isNaN = function(value) { // NaN is the only value that is not equal to itself return value !== value; };}
Note: Use accessor descriptors (get/set) for computed
properties. Use data descriptors (value/writable) for methods. Never mix both in
the same descriptor.
5. UMD and ES Module Polyfill Patterns
Format
Detection
Export Pattern
Use Case
CommonJS
typeof module !== 'undefined'
module.exports = polyfill
Node.js environments
AMD
typeof define === 'function' && define.amd
define([], factory)
RequireJS, legacy browsers
ES Module
Separate .mjs file
export default polyfill
Modern bundlers, native ESM
Global
Fallback for all
window.polyfill = ...
Browser script tags
UMD
Combines all patterns
Check order: AMD, CommonJS, Global
Universal compatibility
Example: UMD wrapper pattern
// Universal Module Definition (UMD) Pattern(function(root, factory) { 'use strict'; // AMD (RequireJS) if (typeof define === 'function' && define.amd) { define([], factory); } // CommonJS (Node.js) else if (typeof module === 'object' && module.exports) { module.exports = factory(); } // Browser globals else { root.myPolyfill = factory(); }}(typeof self !== 'undefined' ? self : this, function() { 'use strict'; // Feature detection if ('myFeature' in window) { return window.myFeature; } // Polyfill implementation function MyPolyfill() { // Implementation here } MyPolyfill.prototype.method = function() { // Method implementation }; // Install globally if needed if (typeof window !== 'undefined') { window.myFeature = MyPolyfill; } // Return for module systems return MyPolyfill;}));// ES Module format (separate file)// polyfill.mjsexport default function polyfill() { if (!Array.prototype.at) { Array.prototype.at = function(index) { var len = this.length; var k = index >= 0 ? index : len + index; return (k >= 0 && k < len) ? this[k] : undefined; }; }}// Usage in ES modules// import polyfill from './polyfill.mjs';// polyfill();
Note: For maximum compatibility, use UMD pattern in polyfills.
Modern projects can use ES modules (.mjs) with build tool transpilation for
legacy support.
6. Idempotency and Safe Execution Patterns
Pattern
Implementation
Purpose
Benefit
Existence Check
if (!Type.prototype.method)
Only add if missing
Prevent double-loading issues
Early Return
if (hasFeature) return;
Exit immediately if native exists
Zero overhead for modern browsers
Version Check
if (polyfill.version) return;
Track polyfill installation
Avoid conflicts with other polyfills
Strict Equality
feature === undefined
Precise undefined checking
Distinguish from null or falsy values
IIFE Isolation
(function(){ ... })()
Create private scope
Prevent variable name collisions
Namespace Guard
window.POLYFILLS = {}
Track loaded polyfills
Coordinate multiple polyfill scripts
Example: Idempotent polyfill patterns
// Pattern 1: Simple existence check(function() { 'use strict'; // Early return if already exists if (Array.prototype.includes) { return; } // Polyfill implementation Array.prototype.includes = function(search) { // Implementation... };})();// Pattern 2: Version tracking(function() { 'use strict'; // Check if already loaded if (window.__POLYFILLS__ && window.__POLYFILLS__.arrayIncludes) { return; } // Initialize polyfill registry window.__POLYFILLS__ = window.__POLYFILLS__ || {}; if (!Array.prototype.includes) { Array.prototype.includes = function(search) { // Implementation... }; } // Mark as loaded window.__POLYFILLS__.arrayIncludes = '1.0.0';})();// Pattern 3: Safe multiple execution(function(global) { 'use strict'; // Create polyfill only once function createPolyfill() { // Check each feature individually if (!Array.prototype.find) { Object.defineProperty(Array.prototype, 'find', { value: function(predicate) { /* ... */ }, configurable: true, writable: true, enumerable: false }); } if (!Array.prototype.findIndex) { Object.defineProperty(Array.prototype, 'findIndex', { value: function(predicate) { /* ... */ }, configurable: true, writable: true, enumerable: false }); } } // Safe to call multiple times - only executes missing polyfills createPolyfill();})(typeof window !== 'undefined' ? window : global);
Key Takeaways - Polyfill Writing
Always wrap polyfills in IIFE with strict mode
Use feature detection before adding any polyfill
Set enumerable: false when extending prototypes
Match native error behavior with proper type checking
Use UMD pattern for maximum compatibility
Make polyfills idempotent - safe to load multiple times