在使用Babel时,为什么需要@babel/polyfill?

6

我正在学习庞大的JavaScript生态系统,但是我无法理解以下内容。

Babel是一个转换器,官方网站上说:

Babel是一个工具链,主要用于将ECMAScript 2015+代码转换为当前和旧版浏览器或环境中向后兼容的JavaScript版本。

由于我使用了 @babel/preset-env,因此我认为只要根据我的browserslist编写 ES6+ 代码,并将其转换为一些兼容的代码就足够了。

然后,我找到了这个页面:https://babeljs.io/docs/en/babel-polyfill,建议使用 @babel/polyfill 而不是 :

import "core-js/stable";
import "regenerator-runtime/runtime";

现在不再使用已弃用的@babel/polyfill。我知道polyfill是什么了,例如,我使用Intersection Observer polyfill。

我的问题是:Babel是否提供了类似插件自动填充代码的功能?他们所提到的这两个库是什么?为什么我需要这两个附加包使我的代码符合ES5标准,如果Babel本应该自己完成这一任务?考虑Object.assign:只有使用core-js包才能在IE11中工作。为什么Babel没有对其进行转译?

编辑:我读错了文章,但我的问题仍然存在。


实际上,该页面指出:“自Babel 7.4.0起,该包(babel / polyfill)已被弃用”,并建议您使用这些导入。 - Heretic Monkey
是的,但它说我应该使用@abel/polyfill。 - gremo
regenerator-runtime是Facebook发布的用于填充生成器的支持运行时。当async/await对Javascript来说还是一个新概念,而生成器还不可用时,它就已经存在了。请注意版权所有2013年:http://facebook.github.io/regenerator/ - user120242
不,它并没有说你应该使用babel/polyfill。页面顶部的大警告,带有警报图像,表示该软件包已被弃用,意味着没有人应该再使用它(如果他们正在使用Babel 7.4.0之后的版本)。它保留了解释如何使用它的文本,因为仍有人没有升级到Babel 7.4.0以上版本,因此无法利用其他polyfill。 - Heretic Monkey
文档没有告诉你只有在必须支持IE或其他情况下才需要使用这些东西吗?我记得5年前就是这种情况。然后所有的抱怨都是因为polyfill重命名导致代码出错,但这主要是因为人们“做错了”。 - user120242
3个回答

11
Polyfill和Transpilation的共同点是让你在旧环境中使用新功能(例如,比较旧版和新版浏览器),主要区别在于Polyfill通过在旧环境中实现该功能来实现。因此,如果我们按照ES6 ES5术语,Polyfill通过在ES5中实现它使您能够使用新功能,但是有些新功能永远无法在ES5中实现,例如ES6引入的Arrow语法-这就需要转译。

需要转译的示例是箭头语法(() => {}),因为您永远无法在ES5中实现它,而可以使用Polyfill的示例是如果您想要实现String.prototype.includes方法,可以像这样实现:

// taken from mdn
if (!String.prototype.includes) {
  String.prototype.includes = function(search, start) {
    'use strict';

    if (search instanceof RegExp) {
      throw TypeError('first argument must not be a RegExp');
    } 
    if (start === undefined) { start = 0; }
    return this.indexOf(search, start) !== -1;
  };
}

现在另一个重要的区别是如果存在本地功能,则polyfill将使用本地功能,但转译不会。这导致结论,出于安全和性能原因,应该优先使用polyfill而不是转译。
最后一个区别是转译涉及语言语法,而polyfill涉及语言语法和本机浏览器API。
长话短说:转译发生在编译时,而polyfill发生在运行时。
现在我们已经清楚地看到,为了使用新的代码和功能,Babel使用这两种策略。主要指南是尽可能使用polyfill;否则,转译(转译将需要新的语法,无法在旧的ES5环境中实现)。所以您需要导入core-js来填充可以通过转译启用的功能,但最好使用polyfill实现它们。
让我们以一些代码作为例子,来区分这两种情况:
const f = (str) => {
  return str.includes('fun')
}

Babel将会把那段代码转译为以下类似的内容:

var f = function f() {
 // notice that `.includes()` stays. Even though this is
 // an ES6 feature, it stays because
 // Babel does not transpile it.
 // 
 // the following code will break if you don't import
 // a polyfill using core-js or any other polyfill library
 return str.includes('fun');
}

我删减了很多Babel转译输出的内容,如果你想看可以在这里阅读。

现在回答你的问题,Babel是否使用自动化工具进行转译。答案是肯定的,这个工具就是@babel/preset-env,它会根据你的目标环境自动配置转译过程和所需的polyfills。


感谢您长篇详细的解释。我在阅读文章时犯了一个错误(实际上是建议放弃使用@babel/polyfill),但我的问题仍然存在。如果Babel将我的代码转换回ES5,为什么我需要core-js才能使Object.assign在IE11中可用?Babel应该将其转换为在不支持它的浏览器中运行的东西。我错过了什么? - gremo
@gremo 我已经编辑了我的回答,更直接地回答了你的问题。 - ehab

1
Babel只提供语言操作(即语法),而不提供所需的基础对象类型(即所作用的名词)。

0

ES6 不仅提供了新的语法,还增加了新的功能,例如:

Number.isInteger(num) 检查 num 是否为整数(没有小数部分的数字)。

ES6 有哪些新特性?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接