什么是 Polyfill?
Polyfill 是一段代码(通常是 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。
名字的由来 🎨
“Polyfill” 这个词来源于一种建筑材料 Polyfilla(一种用于填补墙面裂缝的腻子),形象地表示”填补浏览器功能的空缺”。
为什么需要 Polyfill?
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('banana'));
|
常见的 Polyfill 示例
1. Array.includes Polyfill
if (!Array.prototype.includes) { Array.prototype.includes = function(searchElement, fromIndex) { 'use strict'; const O = Object(this); const len = parseInt(O.length) || 0; if (len === 0) return false; const n = parseInt(fromIndex) || 0; let k = Math.max(n >= 0 ? n : len + n, 0); while (k < len) { if (searchElement === O[k]) return true; k++; } return false; }; }
|
2. Promise Polyfill
if (typeof Promise === 'undefined') { window.Promise = function(executor) { }; }
|
3. Object.assign Polyfill
if (!Object.assign) { Object.assign = function(target) { 'use strict'; if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } const output = Object(target); for (let index = 1; index < arguments.length; index++) { const source = arguments[index]; if (source != null) { for (const key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { output[key] = source[key]; } } } } return output; }; }
|
4. String.padStart Polyfill
if (!String.prototype.padStart) { String.prototype.padStart = function(targetLength, padString) { targetLength = targetLength >> 0; padString = String(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); }; }
|
Polyfill vs 其他概念
1. Polyfill vs Transpile(转译)
Array.prototype.find = Array.prototype.find || function() { };
const add = (a, b) => a + b;
var add = function(a, b) { return a + b; };
|
2. Polyfill vs Shim
- Polyfill:实现标准 API,行为与规范一致
- Shim:可能有自己的 API,不一定遵循标准
如何使用 Polyfill?
1. 手动引入
<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise,Array.from"></script>
|
2. 使用 core-js
npm install core-js
import 'core-js/features/array/includes'; import 'core-js/features/promise';
|
3. 使用 @babel/polyfill(已废弃)
npm install core-js regenerator-runtime
module.exports = { presets: [ ['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3 }] ] };
|
最佳实践
1. 按需加载
if (!window.Promise) { loadScript('promise-polyfill.js'); }
|
2. 使用 polyfill.io 服务
<script src="https://polyfill.io/v3/polyfill.min.js"></script>
|
3. 特性检测
function loadPolyfills() { const polyfills = []; if (!window.Promise) { polyfills.push(import('promise-polyfill')); } if (!Array.prototype.includes) { polyfills.push(import('array-includes-polyfill')); } return Promise.all(polyfills); }
loadPolyfills().then(() => { startApp(); });
|
常用的 Polyfill 库
- core-js - 最全面的 polyfill 库
- polyfill.io - 自动化 polyfill 服务
- es5-shim/es6-shim - ES5/ES6 polyfill
- fetch-polyfill - Fetch API polyfill
- intersection-observer - IntersectionObserver polyfill
注意事项 ⚠️
- 性能影响:Polyfill 会增加代码体积
- 选择性加载:只加载需要的 polyfill
- 版本兼容:确保 polyfill 支持目标浏览器
- 原生优先:优先使用原生实现
if (!Array.prototype.flat) { }
Array.prototype.flat = function() { };
|
总之,Polyfill 是前端开发中实现向后兼容的重要手段,让我们能够在旧浏览器中使用新特性!