Transpiler(转译器) 和 Polyfill(补丁/填充库) 都是用来解决 JavaScript 代码兼容性问题的工具,但它们的工作方式和解决的问题类型完全不同。
核心区别
| 维度 | Transpiler | Polyfill |
|---|---|---|
| 作用对象 | 语法层面 | API/方法层面 |
| 工作原理 | 将新语法转换为旧语法 | 在旧环境中添加缺失的方法 |
| 典型工具 | Babel, TypeScript, Traceur | core-js, polyfill.io |
| 比喻 | 翻译官 | 配件商 |
Transpiler(转译器)
是什么?
将现代 JavaScript 代码 (ES6+)转换成旧版本 JavaScript 代码(ES5),让老浏览器能理解。
工作原理示例
javascript
// 你的现代代码 (ES6+)
const greet = (name) => {
console.log(`Hello ${name}!`);
};
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
// Transpiler (Babel) 转换后 (ES5)
var greet = function(name) {
console.log('Hello ' + name + '!');
};
var numbers = [1, 2, 3];
var doubled = numbers.map(function(n) {
return n * 2;
});
常见语法转换
javascript
// 1. 箭头函数
// Before: () => {}
// After: function() {}
// 2. 模板字符串
// Before: `Hello ${name}`
// After: 'Hello ' + name
// 3. 解构赋值
// Before: const {a, b} = obj
// After: var a = obj.a, b = obj.b
// 4. 展开运算符
// Before: [...arr1, ...arr2]
// After: arr1.concat(arr2)
// 5. 类语法
// Before: class Person {}
// After: function Person() {}
Polyfill(补丁)
是什么?
在旧浏览器中模拟实现缺失的 JavaScript API 和方法。
工作原理示例
javascript
// 现代代码使用了 Array.includes()
const arr = [1, 2, 3];
if (arr.includes(2)) {
console.log('Found!');
}
// 问题:IE 浏览器不支持 Array.includes()
// 解决方案:手动添加这个方法
// Polyfill 实现
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement) {
return this.indexOf(searchElement) !== -1;
};
}
// 现在旧浏览器也能运行了
常见 Polyfill 示例
javascript
// 1. Promise polyfill
if (!window.Promise) {
// 提供 Promise 的完整实现
window.Promise = MyPromiseImplementation;
}
// 2. Object.assign polyfill
if (!Object.assign) {
Object.assign = function(target, ...sources) {
sources.forEach(source => {
if (source) {
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
});
return target;
};
}
// 3. fetch polyfill
if (!window.fetch) {
// 使用 XMLHttpRequest 实现 fetch
window.fetch = function(url, options) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// ... 实现逻辑
});
};
}
实际应用组合
现代前端开发通常同时使用两者:
javascript
// 配置文件示例 (babel.config.js)
module.exports = {
presets: [
['@babel/preset-env', {
// 根据目标浏览器,自动决定需要 transpile 和 polyfill 什么
targets: {
ie: '11',
chrome: '58'
},
// 自动注入需要的 polyfills
useBuiltIns: 'usage',
corejs: 3
}]
]
};
javascript
// 代码示例
// 原始代码
async function getData() {
const response = await fetch('/api/data');
const data = await response.json();
return data.map(item => item.value);
}
// Babel + core-js 转换后(简化版)
// Transpile: async/await -> Promise + generator
// Polyfill: fetch (如果目标环境不支持)
// Polyfill: Array.map (如果目标环境不支持)
形象比喻
Transpiler(翻译官)
scss
中国工程师写中文文档 → 翻译官 → 美国工程师读英文文档
(现代JavaScript) (Babel) (旧JavaScript)
Polyfill(配件商)
scss
你需要一个 USB-C 接口 → 买转接头 (Polyfill) → 在旧电脑上用新设备
(新API调用) (添加实现) (旧环境运行)
实际选择指南
javascript
// 场景1:使用新语法特性 → 需要 Transpiler
const sum = (a, b) => a + b; // 箭头函数
class User { } // class 语法
// 场景2:使用新 API → 需要 Polyfill
Promise.resolve(); // Promise API
Array.from([1,2,3]); // Array.from 方法
'abc'.includes('a'); // String.includes 方法
// 场景3:新语法 + 新 API → 两者都需要
async function test() {
const data = await fetch('/api');
return data.json();
}
// 场景4:新语法但旧环境原生支持 → 不需要 Transpiler
// (比如 Node.js 16+ 支持大部分 ES6 语法)
// 但仍可能需要 polyfill 某些 API
注意事项
-
Transpiler 无法转换 API:箭头函数可以转成普通函数,但 Promise 无法通过"翻译"实现
-
Polyfill 可能不完美:某些 API(如 Proxy)无法完全 polyfill
-
体积问题:完全 polyfill 可能使打包体积增加 100KB+
-
现代实践:
- 使用
@babel/preset-env自动处理 - 按需引入 polyfills (
useBuiltIns: 'usage') - 考虑目标浏览器支持情况
- 使用
javascript
// 推荐做法
// package.json
{
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"IE 11"
]
}
// 代码中无需手动判断,工具自动处理