// This is bad://foo.__proto__.bar = bar;// But this is okayFoo.prototype.bar = bar;
否。两者都在做相同的事情(与
foo.__proto__===Foo.prototype),都很好。他们只是
bar在
Object.getPrototypeOf(foo)对象上创建属性。
语句所指的是分配给
__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该页面上的警告更加详细:
根据 现代Javascript引擎 如何 优化属性访问 的性质,使对象的[[Prototype]]突变是非常缓慢的操作
他们只是简单地指出, 更改 现有对象 的原型链会 终止优化 。相反,您应该通过创建具有不同原型链的新对象
Object.create()。
我找不到明确的引用,但是如果我们考虑如何实现V8的隐藏类,则可以看到此处可能发生的情况。更改对象的原型链时,其内部类型会更改-
它不会像添加属性时那样简单地成为子类,而是会被完全交换。这意味着将刷新所有属性查找优化,并且将需要丢弃预编译的代码。或者,它只是退回到未优化的代码。
一些引人注目的报价:
可写的__proto__难以实施(必须序列化以进行循环检查),并且会产生各种类型混淆的危害。
允许脚本改变几乎所有对象的原型,这使得推理脚本的行为变得更加困难,并使VM,JIT和分析实现变得更加复杂和错误。由于__proto__的可变性,类型推断存在多个错误,并且由于此功能而无法维护多个所需的不变式(即“类型集包含可以实现var / property的所有可能的类型对象”和“ JSFunction的类型也都是函数”) )。
创建后的原型突变,其不稳定的性能不稳定,以及对代理和[[SetInheritance]]的影响
我不希望通过使原型不可重写来获得巨大的性能提升。在未优化的代码中,您必须检查原型链,以防原型对象(而不是其标识)已更改。在优化代码的情况下,如果有人写原始协议,则可以退回到非优化代码。因此,至少在V8曲轴中,它并不会带来太大变化。
设置__proto__时,不仅会浪费该离子对该对象进行未来优化的机会,而且还会迫使引擎爬行到所有其他类型推断(有关函数返回值的信息,或属性值),以为他们知道这个对象,也不告诉他们也不要做很多假设,这涉及进一步的优化以及现有jitpre的失效。在执行过程中更改对象的原型确实是一个令人讨厌的大锤,我们唯一必须避免犯错的方法就是安全地运行它,但是安全是缓慢的。


![为什么对象的[[prototype]]进行突变会降低性能? 为什么对象的[[prototype]]进行突变会降低性能?](http://www.mshxw.com/aiimages/31/405034.png)
