为什么改变对象的 [[prototype]] 会降低性能?

2024-05-20

来自 MDN 文档standard setPrototypeOf功能 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf以及非标准 __proto__财产 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto:

强烈建议不要改变对象的 [[Prototype]],无论这是如何实现的,因为它非常慢,并且不可避免地会减慢现代 JavaScript 实现中的后续执行速度。

Using Function.prototype添加属性是the向 javascript 类添加成员函数的方法。然后如下图所示:

function Foo(){}
function bar(){}

var foo = new Foo();

// This is bad: 
//foo.__proto__.bar = bar;

// But this is okay
Foo.prototype.bar = bar;

// Both cause this to be true: 
console.log(foo.__proto__.bar == bar); // true

Why is foo.__proto__.bar = bar;坏的?如果它不是坏事Foo.prototype.bar = bar;同样糟糕吗?

那么为什么会出现这个警告:它非常慢,并且不可避免地减慢现代 JavaScript 实现中的后续执行速度。一定Foo.prototype.bar = bar;还不错。

Update也许突变意味着重新分配。查看已接受的答案。


// This is bad: 
//foo.__proto__.bar = bar;

// But this is okay
Foo.prototype.bar = bar;

不。两者都在做同样的事情(如foo.__proto__ === Foo.prototype),两者都很好。他们只是在创建一个bar财产在Object.getPrototypeOf(foo) object.

该语句所指的是分配给__proto__财产本身:

function Employee() {}
var fred = new Employee();

// Assign a new object to __proto__
fred.__proto__ = Object.prototype;
// Or equally:
Object.setPrototypeOf(fred, Object.prototype);

警告位于Object.prototype page https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf更详细地说:

改变对象的 [[Prototype]] 本质上是现代 JavaScript 引擎优化属性访问,一个非常慢的操作

他们只是简单地指出改变原型链已经存在的对象杀死优化。相反,您应该通过以下方式创建具有不同原型链的新对象Object.create().

我找不到明确的参考资料,但如果我们考虑如何V8的隐藏类 http://web.archive.org/web/20181001211801/https://github.com/v8/v8/wiki/Design%20Elements已实施(并且最近写的 https://v8.dev/docs/hidden-classes),我们可以看看这里会发生什么。当改变一个对象的原型链时,它的内部类型就会改变——它不会像添加属性时那样简单地变成子类,而是完全交换。这意味着所有属性查找优化都将被刷新,并且预编译代码将需要被丢弃。或者它只是退回到未优化的代码。

一些值得注意的引言:

  • 布伦丹·艾奇(你认识他)说 http://brendaneich.com/2011/01/harmony-of-my-dreams/#div-comment-6121

    可写_proto_ 实现起来非常痛苦(必须序列化以进行循环检查),并且它会造成各种类型混淆的危险。

  • 布赖恩·哈克特(Mozilla)说 https://bugzilla.mozilla.org/show_bug.cgi?id=642500:

    允许脚本改变几乎任何对象的原型会使推断脚本的行为变得更加困难,并使 VM、JIT 和分析实现变得更加复杂和错误较多。由于可变的_,类型推断有几个错误proto_ 并且由于这个特性而无法维持几个理想的不变量(即“类型集包含可以为 var/property 实现的所有可能的类型对象”和“JSFunctions 具有也是函数的类型”)。

  • 杰夫·瓦尔登说 http://mozilla.6506.n7.nabble.com/Fwd-B-3-1-The-proto-pseudo-property-tp279415p279620.html:

    创建后的原型突变,其不稳定的性能不稳定,以及对代理和[[SetInheritance]]的影响

  • 埃里克·科里(谷歌)说 http://esdiscuss.org/topic/standardizing-proto#content-44:

    我并不期望通过使原型不可重写来获得巨大的性能提升。在非优化代码中,您必须检查原型链,以防原型对象(而不是其身份)发生更改。在优化代码的情况下,如果有人编写原型,您可以回退到非优化代码。因此,至少在 V8 曲轴方面,不会产生太大差异。

  • 埃里克·福斯特(Mozilla)说 https://bugzilla.mozilla.org/show_bug.cgi?id=984146#c5

    当你设置_proto_,您不仅破坏了未来从 Ion 对该对象进行优化的任何机会,而且还迫使引擎爬行到类型推断的所有其他部分(有关函数返回值或属性值的信息) ,也许)认为他们了解这个对象并告诉他们也不要做出很多假设,这涉及进一步的去优化,甚至可能使现有的 jitcode 失效。
    在执行过程中改变对象的原型确实是一个令人讨厌的大锤,我们必须避免出错的唯一方法就是谨慎行事,但安全是缓慢的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么改变对象的 [[prototype]] 会降低性能? 的相关文章

随机推荐