For example, there are objects that have similar structure but not exactly the same.
const arr = [
{ name: 'john', age: 12 },
{ name: 'marry', age: 24, married: true }
]
or
const obj = {
john: { age: 12 },
marry: { age: 24, married: true }
}
Let's say John is not married so he does not need married
key. (Though it might be better to have 'married' as false for consistency.) This might not be a perfect example, but in either case is including married
key and keeping the object structure consistent help performance by any chance? e.g. Maybe it might help CPU write the data to the memory faster...?
CodePudding user response:
The performance benefits are:
- Almost certainly tiny, and
- Almost certainly going to vary between JS engines
and aren't worth worrying about unless:
- Your code is running too slow, and
- Profiling implicates the section of the code that is concerned with creating/manipulating these objects
The real concern is maintainability. Maintaining a consistent set of attributes for logically related objects is a good thing, even if it's unnecessary; if someone wants to build on your code, it's nice if they can rely on a fixed set of attributes for a given collection of objects. Default to including the extra attributes consistently; if you get a performance boost, that's just gravy.
CodePudding user response:
Standard disclaimers aside (everything said here may vary between engines, or even between different versions of the same engine, this is just an implementation detail, measure before optimizing, think twice before optimizing at the expense of readability, blah blah blah…), I think it’s reasonable to answer this with a cautious ‘yes’. At the very least, it shouldn’t hurt to ensure objects always have the same shape.
In the case of V8 in particular, there is the somewhat well-known hidden class optimization, which optimizes memory layout of objects based on their dynamically-profiled contents. With fewer object shapes at runtime, there will be fewer hidden classes to track, and the ones that are there can be reused in more situations. The engine will also not have to look up cached data for multiple hidden classes, which can decrease CPU cache contention.
What constitutes an object’s ‘shape’ will of course vary, but there are a number of characteristics you can expect to be relevant:
- What properties are present;
- In which order properties are added to the object (sensitivity to this is sometimes called path dependence);
- Whether the properties are modified after construction;
- The types of values held in those properties, and even particular sub-ranges of those types (e.g. V8 is known to store integers in the range [−231, 231) more efficiently than other numbers, even as the JS number type nominally covers all IEEE 754 doubles).
Though the above is mostly based on V8, you can expect any other optimizing JavaScript engine to perform roughly similar optimizations based on object shape. In fact, even the relatively naïve QuickJS caches object shapes to speed up property lookups.
And writing your code in a way that ensures that objects of conceptually the same ‘type’ have consistent shapes (for example, by having them always constructed in a single place in code, where the same properties are added in the same order) much of the time should not even hurt readability — on the contrary, it might even make code more easily comprehensible. Unlike some other micro-optimizations, I think this one is definitely worth doing to at least some extent.