【问题标题】:ES6 to ES5: Babel's implementation of class extensionES6 到 ES5:Babel 对类扩展的实现
【发布时间】:2018-06-29 20:02:20
【问题描述】:

由于旧的浏览器支持,我们都使用 babeljs 将 ES6 转译成 ES5。当 babel 编译从另一个类扩展的类时。部分编译后的代码是这样的:

...
if (superClass)
    Object.setPrototypeOf
      ? Object.setPrototypeOf(subClass, superClass)
      : (subClass.__proto__ = superClass);
...

顶部代码块用于从父类扩展静态属性。他们使用Object.setPrototypeOf 更改了子类的[[Prototype]]。不要混淆.prototype[[Prototype]] 是完全独立的东西。

MDN 在其参考中关于Object.setPrototypeOf 的使用说明如下:

根据现代 JavaScript 引擎优化属性访问的本质,在每个浏览器和 JavaScript 引擎中,更改对象的 [[Prototype]] 是一项非常缓慢的操作。

我的问题出现在这里:如果我们可以用另一种方式达到相同的结果,为什么 Babel 使用Object.setPrototypeOf?我试图通过循环遍历构造函数 Function 对象从父类(我之前分配给它)中复制所有静态方法。

...
var parentStaticProps = parentClass.prototype.constructor;

for (var prop in parentStaticProps) {
  childClass.prototype.constructor[prop] = parentStaticProps[prop];
}
...

而且它也比 babel 的实现要快!我创建了类似 babel 扩展类的东西,并在jsPerf 中对其进行了测试。 我对Object.setPrototypeOf 的前 5 次测试运行结果非常令人失望:慢了 19%、慢了 20% 和慢了三倍 21%。

我知道Object.setPrototypeOf 可能需要使用一定有一些原因。我想知道。如果是关于不可枚举的属性,那么我们当然可以使用其他一些方法。

【问题讨论】:

  • 在 Edge 中慢了 44%

标签: javascript ecmascript-6 babeljs ecmascript-5


【解决方案1】:

如果我们可以用另一种方式达到相同的结果,为什么 Babel 使用Object.setPrototypeOf

仅仅是因为没有其他方法可以达到相同的结果。仅复制所有属性的当前值与从另一个对象动态继承不同。 Babel 的目标是正确,而不是快速。

而且它也比 babel 的实现要快!我已经创建了类似于 babel 扩展类并在 jsPerf 中对其进行测试的东西。

好吧,创建和扩展类很慢,但这并不重要。 使用这些类——例如访问静态属性——是这里的重要方面。通常没有问题是你改变一个新的(但未使用的)对象的 [[prototype]] - 警告更关心在对象生命周期的中间进行突变。

【讨论】:

  • 我在这里只是复制值很愚蠢。感谢您的回复,我阅读了您对类似主题的另一个问题的回复。不可能达到同样的结果吗?您是自己尝试还是只是在 babel 上进行中继?
  • 是的,如果不使用 Object.setPrototypeOf 或已弃用的 __proto__ 等 ES6 功能,就不可能获得相同的结果。 (我什么都没尝试也没查Babel,只知道没有其他的原语可以达到这个效果)
  • @ChristopherSwasey 我不关注 - 在子类上调用 setPrototypeOf 不会影响在基类上使用 new 的性能?
  • @ChristopherSwasey “一旦扩展”是什么意思? ES5 构造函数如何知道它已被“扩展”?我可能会想象instanceof Base 在编译后的代码中变成多态的,但这与setPrototypeOf 无关,仅与Base.call(subclassInstance) 有关。
猜你喜欢
  • 2019-11-18
  • 2017-11-05
  • 1970-01-01
  • 2018-11-28
  • 2016-05-13
  • 1970-01-01
  • 2020-05-29
  • 2016-02-28
  • 1970-01-01
相关资源
最近更新 更多