为什么改变对象的[[prototype]]对性能有害? [英] Why is mutating the [[prototype]] of an object bad for performance?

查看:199
本文介绍了为什么改变对象的[[prototype]]对性能有害?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自标准的 setPrototypeOf 功能以及非标准 __ proto __ property

From the MDN docs for the standard setPrototypeOf function as well as the non-standard __proto__ property:


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

Mutating the [[Prototype]] of an object, no matter how this is accomplished, is strongly discouraged, because it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations.

使用 Function.prototype 添加属性 方式将成员函数添加到javascript类。然后如下所示:

Using Function.prototype to add properties is the way to add member functions to javascript classes. Then as the following shows:

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

为什么 foo .__ proto__.bar = bar; 不好?如果它的错误不是 Foo.prototype.bar = bar; 同样糟糕?

Why is foo.__proto__.bar = bar; bad? If its bad isn't Foo.prototype.bar = bar; just as bad?

然后为什么会出现这样的警告: 它很慢并且不可避免地减慢了现代JavaScript实现中的后续执行速度 。当然 Foo.prototype.bar = bar; 并不是那么糟糕。

Then why this warning: it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations. Surely Foo.prototype.bar = bar; is not that bad.

更新也许通过突变他们意味着重新分配。见接受的答案。

Update Perhaps by mutation they meant reassignment. See accepted answer.

推荐答案


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

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


否。两者都在做同样的事情(如 foo .__ proto__ === Foo.prototype ),两者都很好。他们只是在 Object.getPrototypeOf(foo)对象上创建一个 bar 属性。

No. Both are doing the same thing (as foo.__proto__ === Foo.prototype), and both are fine. They're just creating a bar property on the Object.getPrototypeOf(foo) object.

该陈述所指的是分配给 __ proto __ 属性本身:

What the statement refers to is assigning to the __proto__ property itself:

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 详细介绍:

The warning at the Object.prototype page goes into more detail:


根据现代JavaScript引擎如何优化属性访问的性质,对对象的[[Prototype]]进行变换 ,一个非常慢的操作

Mutating the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation

他们只是声明更改已存在对象的原型链 杀死优化。相反,你应该通过 Object.create()创建一个具有不同原型链的新对象。

They simply state that changing the prototype chain of an already existing object kills optimisations. Instead, you're supposed to create a new object with a different prototype chain via Object.create().

我找不到明确的参考,但如果我们考虑如何 V8的隐藏类已经实现,我们可以看到这里可能会发生什么。当更改对象的原型链时,其内部类型会发生变化 - 它不会像添加属性时那样简单地成为子类,而是完全交换。这意味着刷新所有属性查找优化,并且需要丢弃预编译代码。或者它只是回退到非优化代码。

I couldn't find an explicit reference, but if we consider how V8's hidden classes are implemented, we can see what might go on here. When changing the prototype chain of an object, its internal type changes - it does not simply become a subclass like when adding a property, but is completely swapped. It means that all property lookup optimisations are flushed, and precompiled code will need to be discarded. Or it simply falls back to non-optimized code.

一些值得注意的报价:


可写__proto__是一个巨大的痛苦要实现(必须序列化循环检查)并创建各种类型 - 混淆危险。

Writable __proto__ is a giant pain to implement (must serialize to cycle-check) and it creates all sorts of type-confusion hazards.


  • Brian Hackett(Mozilla)说


    允许脚本改变漂亮的原型任何对象都使得更难以推断脚本的行为并使VM,JIT和分析实现更加复杂和繁琐。类型推断由于可变的__proto__而有几个错误,并且因为这个特性而不能维护几个理想的不变量(即'类型集包含可以为var / property实现的所有可能的类型对象'和'JSFunctions具有也是函数的类型' )。

    Allowing scripts to mutate the prototype of pretty much any object makes it harder to reason about the behavior of a script and makes VM, JIT, and analysis implementation more complex and buggier. Type inference has had several bugs due to mutable __proto__ and cannot maintain several desirable invariants because of this feature (i.e. 'type sets contain all the possible type objects which can realized for a var/property' and 'JSFunctions have types which are also functions').


  • Jeff Walden说


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

    Prototype mutation after creation, with its erratic performance destabilization, and the impact upon proxies and [[SetInheritance]]


  • Erik Corry(谷歌)说


    我不认为使proto不可覆盖会带来很大的性能提升。在非优化代码中,您必须检查原型链,以防原型对象(而不是其标识)已更改。在优化代码的情况下,如果有人写入proto,您可以回退到非优化代码。所以它不会产生那么大的差别,至少在V8-Crankshaft中。

    I don't expect big performance gains from making proto non-overwritable. In non-optimized code you have to check the prototype chain in case the prototype objects (not their identity) have been changed. In the case of optimized code you can fall back to nonoptimized code if someone writes to proto. So it wouldn't make all that much difference, at least in V8-Crankshaft.


  • Eric Faust(Mozilla)说


    当您设置__proto__时,不仅会破坏您对该对象上的Ion进行未来优化的任何机会,而且还会强制引擎爬行到所有其他类型推断的部分(可能是关于函数返回值或属性值的信息),他们认为他们知道这个对象,并告诉他们不要做出许多假设,这涉及到进一步的去优化以及可能使现有jitcode无效。

    更改在执行过程中对象的原型实际上是一个讨厌的大锤,我们必须避免错误的唯一方法是保证安全,但安全性很慢。

    When you set __proto__, not only are you ruining any chances you may have had for future optimizations from Ion on that object, but you also force the engine to go crawling around to all the other pieces of type inference (information about function return values, or property values, perhaps) which think they know about this object and tell them not to make many assumptions either, which involves further deoptimization and perhaps invalidation of existing jitcode.
    Changing the prototype of an object in the middle of execution is really a nasty sledgehammer, and the only way we have to keep from being wrong is to play it safe, but safe is slow.


  • 这篇关于为什么改变对象的[[prototype]]对性能有害?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆