Reputation: 6726
In V8, an object changes its hidden class when a new property is added.
function Point(x, y) {
this.x = x; // This will create new hidden class
this.y = y; // This too
}
My question is simple, will this create a new hidden class?
Point.prototype.z = null;
I ask this question because in a coding style guideline I have read, they said we should declare class properties by creating a prototype instead of assigning them in the constructor. This will also help us to easily document them with JSDoc.
Thanks a lot.
Upvotes: 11
Views: 866
Reputation: 10492
The answer is yes: a new hidden class will be created. However it's important to understand that it will be the prototype object itself that will change its hidden class, not an object created by the Point constructor.
Any object has a hidden class attached to it. Lets look at the code
var o = new Point();
o.z = 0; // (1)
Point.prototype.zz = 0; // (2)
At any given moment any object has a hidden class, that means o
, o.__proto__
, o.__proto__.__proto__
have a distinctive hidden class associated with them.
When you add a new property to the object, it's only hidden class of that object that changes. If you change hidden class of the prototype, the hidden classes of objects that share that prototype do not change. There is no need for such a change because we don't expect hidden class of an object X
to fully describe the layout of any object in its whole prototype chain, its hidden class describes layout of X
and X
alone. Furthermore it's simply infeasible to implement such downwards propagation: that would require VM to maintain backward links between prototypes and all associated objects: to be able at any moment for an object X
to enumerate all objects Y
that have Y.__proto__ === X
.
For the code above that means that statement (1)
changes only the hidden class of o
and statement (2)
changes only the hidden class of Point.prototype
(which is the same object as o.__proto__
) but not of o
itself.
Furthermore if you consider the code like this:
Point.prototype.z = 0; // Initial value
var o1 = new Point();
o1.z = 11; // (3)
var o2 = new Point();
which is sometimes recommended then this is a performance antipattern precisely because hidden classes of o1
/ o2
and Point.prototype
are disconnected. Assignment at (3)
would change the hidden class of o1
even though o1.__proto__
already has property z
. Objects o1
and o2
will end up having different hidden classes which will cause all the code that uses both of them to go polymorphic and penalize the performance. Furthermore o1
will end up using more space than in case if z
was added right in the constructor because z
would be stored in the out-of-object property storage.
Upvotes: 5