From the MDN docs for the standard setPrototypeOf
function as well as the non-standard __proto__
property:
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.
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
Why is foo.__proto__.bar = bar;
bad? If its bad isn't Foo.prototype.bar = bar;
just as bad?
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.
Here is a benchmark using node
v6.11.1
NormalClass: A normal class, with the prototype non edited
PrototypeEdited: A class with the prototype edited (the
test()
function is added)PrototypeReference: A class with the added prototype function
test()
who referer to an external variableResults :
As you can see, the prototype edited class is a way faster than the normal class. The prototype who has a variable which refer to an external one is the slowest, but that's an interesting way to edit prototypes with already instantied variable
Source :
No. Both are doing the same thing (as
foo.__proto__ === Foo.prototype
), and both are fine. They're just creating abar
property on theObject.getPrototypeOf(foo)
object.What the statement refers to is assigning to the
__proto__
property itself:The warning at the
Object.prototype
page goes into more detail: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()
.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.
Some notable quotes:
Brendan Eich (you know him) said
Brian Hackett (Mozilla) said:
Jeff Walden said:
Erik Corry (Google) said:
Eric Faust (Mozilla) said
Yes .prototype= is just as bad, hence the wording "no matter how it is accomplished". prototype is a pseudo object for extending the functionality at the class level. Its dynamic nature slows down script execution. Adding a function on the instance level, on the other hand, incurs far less overhead.
__proto__
/setPrototypeOf
aren't the same as assigning to the object prototype. For example, when you have a function/object with members assigned to it:Everybody seem to be focusing only on the prototype, and forget that functions can have members assigned to it and instantiated after mutation. There's currently no other way of doing this without using
__proto__
/setPrototypeOf
. Barely anyone use a constructor without the ability to inherit from a parent constructor function, andObject.create
fails to serve.And plus, that's two
Object.create
calls, which at the present moment, is ungodly slow in V8 (both browser and Node), which makes__proto__
a more viable choice