将 ES8 特性转译到 ES5
BabelJS - 将 ES2017 (ES8) 特性转译到 ES5
Section titled “BabelJS - 将 ES2017 (ES8) 特性转译到 ES5”ECMAScript 2017(通常称为 ES8)为 JavaScript 引入了几个重要的特性。对于需要支持旧环境的项目,BabelJS 是将这些特性转译(Transpiling)到与 ES5 兼容的代码的关键工具。主要使用的工具是 @babel/preset-env,通常与 core-js 结合使用,为新特性提供 Polyfill(垫片)。
ES2017 的主要特性包括:
- 异步函数(Async Functions) (
async/await) - Object.values() / Object.entries()
- 字符串填充(String padding) (
padStart()/padEnd()) - Object.getOwnPropertyDescriptors()
- 函数参数列表和调用中的尾随逗号(Trailing commas)
我们将重点介绍其中的一些特性以及 Babel 如何处理它们。假设你已经使用 @babel/preset-env 和 core-js 设置了 Babel 以提供 Polyfill。
用于 Polyfill 的 Babel 配置
Section titled “用于 Polyfill 的 Babel 配置”对于那些是新方法或对象(而不仅仅是语法)的特性,需要 Polyfill。更新你的 babel.config.json 文件:
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 } ] ]}并确保已安装 core-js:
npm install --save core-js1. 异步函数(Async Functions) (async/await)
Section titled “1. 异步函数(Async Functions) (async/await)”异步函数(Async functions)提供了一种更简洁的方式来处理基于 Promise 的异步操作,使异步代码看起来和行为更接近同步代码。
ES2017 代码(示例:async_example.js)
Section titled “ES2017 代码(示例:async_example.js)”function resolveAfter2Seconds() { return new Promise(resolve => { setTimeout(() => { resolve('resolved'); }, 2000); });}
async function asyncCall() { console.log('calling'); const result = await resolveAfter2Seconds(); console.log(result); // 预期输出: "resolved"}
asyncCall();@babel/preset-env(它包含了 @babel/plugin-transform-async-to-generator 插件)将异步函数转译为 generator 函数(generator functions)。这也需要 regenerator-runtime(通过上面配置的 core-js 或 @babel/plugin-transform-runtime 插件来处理)。
npx babel async_example.js --out-file async_example_es5.js转译后的 ES5 代码(简化版,包含辅助函数)
Section titled “转译后的 ES5 代码(简化版,包含辅助函数)”// 顶部可能包含 core-js/regenerator-runtime 的导入// import "core-js/modules/es.object.to-string.js";// import "core-js/modules/es.promise.js";// import "regenerator-runtime/runtime.js";
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { /* ... 辅助函数 ... */ }
function _asyncToGenerator(fn) { /* ... 辅助函数 ... */ }
function resolveAfter2Seconds() { return new Promise(function (resolve) { setTimeout(function () { resolve('resolved'); }, 2000); });}
function asyncCall() { return _asyncCall.apply(this, arguments);}
function _asyncCall() { _asyncCall = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { var result; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: console.log('calling'); _context.next = 3; return resolveAfter2Seconds(); case 3: result = _context.sent; console.log(result); case 5: case "end": return _context.stop(); } } }, _callee); })); return _asyncCall.apply(this, arguments);}
asyncCall();转译后的代码使用 generator 函数和 regeneratorRuntime(由 core-js 或 @babel/runtime 提供)来模拟 async/await 的行为。如果 Promise 在目标环境中不可用,也需要进行 Polyfill。
2. 字符串填充(String Padding) (padStart() / padEnd())
Section titled “2. 字符串填充(String Padding) (padStart() / padEnd())”这些方法使用另一个字符串(如果需要会重复)填充当前字符串,直到结果字符串达到指定的长度。填充是从原始字符串的开头 (padStart) 或结尾 (padEnd) 应用。
ES2017 代码(示例:string_padding.js)
Section titled “ES2017 代码(示例:string_padding.js)”const str = 'abc';
console.log(str.padStart(5, '_')); // Output: "__abc"console.log(str.padStart(2, '_')); // Output: "abc" (length already >= 2)console.log(str.padEnd(8, '*_')); // Output: "abc*_*_*"console.log('test'.padStart(10)); // Output: " test" (pads with spaces by default)这些是 String.prototype 上的新方法。Babel 本身不转译这些方法,但是配合 "useBuiltIns": "usage" 和 core-js,如果你的目标环境需要它们,Babel 会确保包含 String.prototype.padStart 和 String.prototype.padEnd 的 Polyfill。
npx babel string_padding.js --out-file string_padding_es5.js转译后的 ES5 代码 (string_padding_es5.js)
Section titled “转译后的 ES5 代码 (string_padding_es5.js)”// 顶部可能包含 core-js 字符串填充模块的导入// e.g., import "core-js/modules/es.string.pad-start.js";// e.g., import "core-js/modules/es.string.pad-end.js";
"use strict";
var str = 'abc';console.log(str.padStart(5, '_'));console.log(str.padStart(2, '_'));console.log(str.padEnd(8, '*_'));console.log('test'.padStart(10));调用的语法保持不变。功能性由 Babel 导入的 Polyfill 提供(因为使用了 useBuiltIns: 'usage' 选项)。
在浏览器中测试字符串填充
Section titled “在浏览器中测试字符串填充”要在浏览器中测试这一点,尤其是旧浏览器,你需要打包 string_padding_es5.js(如果由支持打包器的 Babel 设置生成,它现在包含 core-js 的导入,或者你需要确保 Polyfill 已全局加载)。
创建 test.html 文件:
<!DOCTYPE html><html><head> <title>BabelJS ES2017 String Padding Test</title></head><body> <p>Check the console for output.</p> <!-- 假设 string_padding_es5.js 已打包或 polyfill 已全局可用 --> <script src="path/to/your/bundled/string_padding_es5.js"></script></body></html>在任何浏览器(现代浏览器或带有 Polyfill 的旧浏览器)中打开时,控制台应显示:
__abcabcabc*_*_* test3. Object.values() 和 Object.entries()
Section titled “3. Object.values() 和 Object.entries()”Object.values() 返回一个给定对象自身可枚举属性值的数组。Object.entries() 返回一个给定对象自身可枚举字符串键属性的 [key, value] 对数组。
ES2017 代码(示例:object_methods.js)
Section titled “ES2017 代码(示例:object_methods.js)”const obj = { a: 1, b: 'hello', c: true };
console.log(Object.values(obj)); // Output: [1, "hello", true]console.log(Object.entries(obj)); // Output: [["a", 1], ["b", "hello"], ["c", true]]与字符串填充类似,这些是 Object 上的新的静态方法。Babel 配合 core-js 将为它们提供 Polyfill。
转译后的 ES5 代码 (object_methods_es5.js)
Section titled “转译后的 ES5 代码 (object_methods_es5.js)”// 顶部可能包含 core-js Object.values/entries 模块的导入// e.g., import "core-js/modules/es.object.values.js";// e.g., import "core-js/modules/es.object.entries.js";
"use strict";
var obj = { a: 1, b: 'hello', c: true};console.log(Object.values(obj));console.log(Object.entries(obj));由于 core-js 提供的 Polyfill,对 Object.values() 和 Object.entries() 的调用可以在旧环境中工作。
Babel 的强大之处在于其通过预设(presets)和插件(plugins)实现的扩展性,并结合像 core-js 这样的 Polyfill 解决方案。这使得开发者可以自信地使用 ES2017 等现代 JavaScript 特性,同时知道他们的代码可以被转换,以便在广泛的目标环境中可靠运行。