Skip to content

将 ES7 特性转译到 ES5

BabelJS - 将 ES2016 (ES7) 特性转译为 ES5

Section titled “BabelJS - 将 ES2016 (ES7) 特性转译为 ES5”

ECMAScript 2016(以前称为 ES7)为 JavaScript 引入了几个值得注意的特性。尽管现代浏览器对这些特性有很好的支持,但如果您要针对较旧的环境,可能需要将它们转译为 ES5。BabelJS,特别是结合 @babel/preset-env,能够处理这些转换。

ES2016 中添加的主要特性是:

  • 指数运算符 (Exponentiation Operator) (**)
  • Array.prototype.includes()

(注意:Async/Await 通常与这个时期相关联,但它在 ES2017 中正式标准化。我们将在单独的章节或作为 ES2017 特性的一部分介绍它的转译,但原理是相似的。)

我们将重点介绍如何将这些特性转译为 ES5。默认情况下,未指定目标的 @babel/preset-env 会将代码转译为 ES5。对于像 Array.prototype.includes() 这样的特性,Babel 不能仅转译语法;它是一个新方法。这需要使用 Polyfill(垫片)。

指数运算符为 Math.pow() 提供了一种简写方式。

ES2016 代码(示例:exponentiation.js)

Section titled “ES2016 代码(示例:exponentiation.js)”
let num = 2;
let powerOfThree = num ** 3; // 2 to the power of 3 // 2 的 3 次方
console.log(`${num} raised to the power of 3 is ${powerOfThree}`); // Outputs: 2 raised to the power of 3 is 8 // 输出:2 的 3 次方是 8
let squared = 5 ** 2;
console.log(`5 squared is ${squared}`); // Outputs: 5 squared is 25 // 输出:5 的平方是 25

要转译这段代码,请确保您已配置 Babel(例如,使用包含 @babel/preset-env 的 babel.config.json)。

{
"presets": ["@babel/preset-env"]
}
npx babel exponentiation.js --out-file exponentiation_es5.js

转译后的 ES5 代码 (exponentiation_es5.js)

Section titled “转译后的 ES5 代码 (exponentiation_es5.js)”
"use strict";
var num = 2;
var powerOfThree = Math.pow(num, 3); // 2 to the power of 3 // 2 的 3 次方
console.log("".concat(num, " raised to the power of 3 is ").concat(powerOfThree)); // Outputs: 2 raised to the power of 3 is 8 // 输出:2 的 3 次方是 8
var squared = Math.pow(5, 2);
console.log("5 squared is ".concat(squared)); // Outputs: 5 squared is 25 // 输出:5 的平方是 25

Babel 正确地将 ** 运算符转换为它的等效 Math.pow() 方法,该方法在所有 ES5 环境中都可用。

Array.prototype.includes() 是一个方便的方法,用于检查数组是否包含某个元素,返回 true 或 false。与指数运算符不同,这是一个添加到 Array.prototype 上的新方法。Babel 不能简单地为此转译语法;它需要一个 polyfill 来在缺少 includes 方法的环境中提供其功能。

ES2016 代码(示例:array_includes.js)

Section titled “ES2016 代码(示例:array_includes.js)”
let numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true // 真
console.log(numbers.includes(6)); // false // 假
let pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // true // 真
console.log(pets.includes('hamster')); // false // 假

如果您只使用 @babel/preset-env 而不配置 polyfill 来转译这段代码,JavaScript 语法本身(方法调用)将基本保持不变,因为它是一个有效的语法。然而,它在没有 Array.prototype.includes 的旧版浏览器中将无法工作。

转译后的 ES5 代码(语法上,尚未应用 polyfill)

Section titled “转译后的 ES5 代码(语法上,尚未应用 polyfill)”
"use strict";
var numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true in modern env, error or undefined in old env // 在现代环境为 true,在旧环境可能报错或 undefined
console.log(numbers.includes(6)); // false in modern env, error or undefined in old env // 在现代环境为 false,在旧环境可能报错或 undefined
var pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // true // 真
console.log(pets.includes('hamster')); // false // 假

为了使 Array.prototype.includes() 在较旧的环境中工作,您需要提供一个 polyfill。使用现代 Babel 的推荐方式是使用 core-js。您可以配置 @babel/preset-env,使其根据您的代码用法和目标环境自动从 core-js 中包含 polyfill。

  1. 安装 core-js:
npm install --save core-js
  1. 更新 babel.config.json:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage", // or "entry" // 或者 "entry"
"corejs": 3 // Specify core-js version // 指定 core-js 版本
}
]
]
}

使用 "useBuiltIns": "usage" 时,Babel 会分析您的代码,并仅针对您使用的、且目标环境不支持的特性添加特定的 import 'core-js/...' 语句。如果未指定目标环境,它会假设为较旧的环境。

现在转译 array_includes.js 文件时,Babel 会在文件顶部添加类似的 import 语句:

// Example of what Babel might add at the top of array_includes_es5.js: // Babel 可能在 array_includes_es5.js 文件顶部添加的示例:
// import "core-js/modules/es.array.includes.js";
// (if using a bundler, otherwise it might be different) // (如果使用打包工具,否则可能会有所不同)
"use strict";
// ... rest of your transpiled code ... // ... 其余的转译代码 ...
var numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3));
// ...

这个导入的 core-js 模块在缺少 Array.prototype.includes 实现时会提供它。现在,即使在支持 ES5 但缺少 includes 的旧版浏览器中,代码也能正确工作。

或者,使用 "useBuiltIns": "entry" 需要您在应用程序的入口点 (entry point) 添加 import "core-js"; 和 import "regenerator-runtime/runtime";(如果使用了 async/generators)。然后 Babel 会根据您的目标环境将这些语句替换为特定的导入。

要在浏览器中测试使用 polyfill 的代码,您通常需要打包 (bundle) 您的 JavaScript 代码(例如,使用 Webpack 或 Rollup),这将解析 core-js 的 import 语句。然后,您的 HTML 文件将包含这个打包后的文件。

test.html(假设打包后的输出文件为 bundle.js):

<!DOCTYPE html>
<html>
<head>
<title>BabelJS ES2016 Test</title> // BabelJS ES2016 测试
</head>
<body>
<p>Check the console for output.</p> // 查看控制台输出。
<script src="bundle.js"></script>
<!-- bundle.js would contain transpiled code + core-js polyfills -->
<!-- bundle.js 将包含转译后的代码 + core-js polyfills -->
</body>
</html>

当您在旧版浏览器中打开这个 HTML 文件时,控制台应该会正确显示:

true
false
true
false

这展示了 Babel 的强大之处,它不仅可以转换语法,还可以结合像 core-js 这样的 polyfill 库,在较旧的 JavaScript 环境中提供缺失的功能。

有关 polyfill 的更多详细信息,请参阅关于 Polyfills 的专门章节以及 Babel 和 core-js 的官方文档。