V8 Hidden Classes in JavaScript: Full Tutorial

V8 uses hidden classes to make object property access fast. Learn how shapes work, why property order matters, and how to write code that stays on V8's fast path.

7 min read

V8 hidden classes are one of the most important internal mechanisms in V8. They are not related to JavaScript's class keyword. They are the way V8 represents the shape of an object so that property access is fast.

In a naive JavaScript engine, every property access would be a dictionary lookup: search the object's keys for the right name, then return the value. Dictionary lookups are slow because they scale with the number of properties. Hidden classes turn property access into a single memory load at a known offset, as fast as accessing a struct field in C.

The Problem Hidden Classes Solve

JavaScript objects are dynamic. You can add properties at any time, delete them, and even change their order. A static compiler cannot determine the memory layout of an object ahead of time.

Hidden classes solve this by tracking the layout at runtime.

When you create an empty object, V8 assigns it a hidden class that says this object has no properties. When you add a property, V8 creates a new hidden class that extends the previous one and records the new property's name and memory offset. The object transitions to the new hidden class.

Other objects that follow the same property-addition sequence share the same hidden classes. When V8 needs to access a property on any of them, it looks up the offset from the hidden class and reads the value directly. No dictionary search.

How Hidden Class Transitions Work

Every time you add a property, the object transitions to a new hidden class. V8 remembers the transition path so it can reuse it.

javascriptjavascript
const obj = {};
// Hidden class HC0: empty object
 
obj.x = 10;
// Transition: HC0 --(add "x")--> HC1: { x at offset 0 }
 
obj.y = 20;
// Transition: HC1 --(add "y")--> HC2: { x at offset 0, y at offset 1 }

Now every empty object that adds x then y follows the same path and ends up with the same hidden class. V8 can hardcode the offset for x as 0 and y as 1 for all objects with hidden class HC2.

A transition tree forms as different objects take different property-addition paths. If one object adds x then y and another adds y then x, they end up at different leaf hidden classes even though they have the same set of properties.

Why Property Order Matters

Two objects with identical properties but different creation order get different hidden classes. This is one of the most important things to understand about V8 performance.

javascriptjavascript
const a = {};
a.x = 1;
a.y = 2;
// Hidden class path: empty --(x)--> HC_A1 --(y)--> HC_A2
 
const b = {};
b.y = 2;
b.x = 1;
// Hidden class path: empty --(y)--> HC_B1 --(x)--> HC_B2

Objects a and b have the same properties with the same values, but different hidden classes. Code that accesses a.x and b.x at the same call site will see two different hidden classes, making the inline cache polymorphic rather than monomorphic.

For consistent hidden classes, always initialize properties in the same order. In constructors, this is usually straightforward: list all the properties you will ever set on the object.

javascriptjavascript
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    // All Point instances follow the same transition path.
    // All end up with the same hidden class.
  }
}

The Hidden Class Transition Tree

As a codebase creates objects in different ways, V8 builds a transition tree. Each node is a hidden class. Each edge is a property addition that leads to the next hidden class.

Hidden class transition tree

The transition tree grows as the program runs. V8 never merges branches. HC3 and HC4 both represent objects with properties x and y, but they are different hidden classes because the properties were added in different orders.

V8 optimizes the tree for fast traversal. Each hidden class stores a mapping from property name to the next hidden class in the transition. Finding the right transition is a single hashtable lookup.

Dictionary Mode: When Hidden Classes Fail

Hidden classes work well for objects with stable shapes. But JavaScript also allows deleting properties and adding properties in unpredictable patterns. When V8 cannot maintain a useful hidden class, it switches the object to dictionary mode.

In dictionary mode, properties are stored in a hashtable rather than at fixed offsets. Property access becomes slower because every access requires a lookup. Adding or deleting properties is faster in dictionary mode, but reading is slower.

V8 switches to dictionary mode when you delete a property from an object. The hidden class chain breaks because the property offsets shift. V8 gives up on hidden classes and moves the object to a dictionary representation.

Avoid deleting properties in performance-sensitive code. Instead of delete obj.x, set obj.x to null or undefined and check for that sentinel value.

Inline Caching and Hidden Classes

Hidden classes enable the most important V8 optimization for property access: inline caching. When the engine encounters obj.x at a particular call site, it caches the hidden class of the object and the offset of property x.

Next time the same call site executes, the engine checks if the object has the expected hidden class. If it does, the engine reads the value directly from the cached offset. If it does not, the engine falls back to a full lookup and updates the cache.

A monomorphic cache handles one hidden class and is the fastest. A polymorphic cache handles two to four hidden classes and is moderately fast. A megamorphic cache has given up and does a full lookup every time.

For guidance on writing cache-friendly code, see /javascript/javascript-v8-engine-internals-complete-guide.

Constructor Functions and Hidden Classes

Constructor functions are the single best opportunity for hidden class optimization. Every object created with the same constructor goes through the same initialization sequence and ends up with the same hidden class.

V8 recognizes constructor patterns and optimizes them aggressively. When it sees many objects created from the same constructor with the same hidden class, all property accesses on those objects become simple offset loads.

The optimization degrades if the constructor code branches. If a constructor sometimes adds a property and sometimes does not, different instances get different hidden classes and inline caches become polymorphic.

Hidden Classes Across Engines

All modern JavaScript engines use some form of hidden classes, though the names differ. V8 calls them Maps or Hidden Classes.

SpiderMonkey calls them Shapes. JavaScriptCore calls them Structures.

The concept is the same across engines: track object layouts at runtime, use transitions when properties are added, and enable fast offset-based property access. The implementation details differ, but the performance implications for your code are consistent: stable object shapes produce fast property access.

For more on how property access works end to end, see /javascript/how-the-google-v8-engine-compiles-javascript.

Rune AI

Rune AI

Key Insights

  • Hidden classes (Maps) are internal structures V8 uses to track object property layouts for fast access.
  • Objects with the same properties in the same order share the same hidden class, enabling offset-based lookup.
  • Adding properties out of order or deleting properties breaks hidden class chains and triggers dictionary mode.
  • Inline caching remembers the hidden class and property offset from the last access, skipping repeated lookups.
  • Initialize all properties in constructors, in the same order, for the best hidden class behavior.
RunePowered by Rune AI

Frequently Asked Questions

Are hidden classes the same as JavaScript classes?

No. Hidden classes (also called Maps or Shapes) are an internal V8 implementation detail for optimizing property access. They have nothing to do with the class keyword, prototype chains, or inheritance.

How do I check the hidden class of an object?

You cannot access hidden classes from JavaScript directly. In Chrome DevTools, you can use the Memory tab heap snapshot to see object shapes. In Node.js, use --allow-natives-syntax and call %DebugPrint(obj) to see the hidden class.

Conclusion

Hidden classes are V8's solution to the problem of fast property access in a dynamic language. By tracking the shape of each object and using inline caching to remember lookups, V8 turns dynamic property access into static offset loads. Writing code that maintains stable hidden classes gives you near-C++ performance for your JavaScript objects.