2

Reading up on V8 (micro) optimization from this old article and there is a quote:

Always initialize object members in the same order

Question: In the example below, what does it mean to Always initialize object members in the same order?

function Point(x, y) {
  this.x = x; // this.x = x line first because x is the first arg
  this.y = y; // this.y = y line second because y is the second arg
}

var p1 = new Point(11, 22);
var p2 = new Point(33, 44);
// At this point, p1 and p2 have a shared hidden class
p2.z = 55;
// warning! p1 and p2 now have different hidden classes!

Longer quote:

JavaScript has limited compile-time type information: types can be changed at runtime, so it's natural to expect that it is expensive to reason about JS types at compile time. This might lead you to question how JavaScript performance could ever get anywhere close to C++. However, V8 has hidden types created internally for objects at runtime; objects with the same hidden class can then use the same optimized generated code.

Until the object instance p2 has additional member ".z" added, p1 and p2 internally have the same hidden class - so V8 can generate a single version of optimized assembly for JavaScript code that manipulates either p1 or p2. The more you can avoid causing the hidden classes to diverge, the better performance you'll obtain.

Therefore:

  • Initialize all object members in constructor functions (so the instances don't change type later)

  • Always initialize object members in the same order

Note: I've found similar questions in C++ but I cant really read it Why should I initialize member variables in the order they're declared in?

Armeen Moon
  • 18,061
  • 35
  • 120
  • 233
  • For example, if your constructor were to have branching logic that causes initialization of `x` and `y` in different order depending on input parameters, that would be violating the recommendation you've quoted. – Patrick Roberts Aug 02 '19 at 04:44
  • could you create an answer + example... I still don't get it. – Armeen Moon Aug 02 '19 at 04:52

1 Answers1

6

V8 developer here. First off, this JavaScript performance advice is completely unrelated to C++'s rules for member initialization. It's also unrelated to the order of constructor arguments, i.e. the following would be perfectly fine from an engine performance point of view:

function Point(x, y) {
  this.y = y;  // Nothing wrong with this.
  this.x = x;
}

What "initialize members in the same order" means is that all instances of that type should use the same initialization order. When they all use the same simple constructor, that happens automatically -- which is great, because that means in most cases, you don't have to worry about this; you don't even need to be aware of the advice.

The most common counter-example is creating objects using object literals, and not caring about the order of properties in there. Even if the set of property names is the same, order matters for hidden classes. Consider:

let p1 = {x: 1, y: 2};
let p2 = {y: 3, x: 4};
// p1 and p2 now have different hidden classes!
function get_x(point) { return point.x; }
get_x(point1);
get_x(point2);

The point.x load in get_x now needs to deal with two hidden classes, which is slightly slower than seeing the same hidden class everytime.

"Always use a constructor" is a good rule of thumb to avoid this; however that's not quite precise enough, as the following example shows:

function SillyPoint(x, y) {
  if (x >= y) {  // or any other condition
    this.x = x;
    this.y = y;
  } else {
    this.y = y;
    this.x = x;
  }
}
let p1 = SillyPoint(1, 2);
let p2 = SillyPoint(2, 1);

Even though p1 and p2 used the same constructor, they initialized their members in different order, so they have different hidden classes. Like in the example above, this makes property loads slightly slower in functions that need to deal with both p1 and p2.

jmrk
  • 34,271
  • 7
  • 59
  • 74