Object Internals: Hidden Classes, Shapes & Inline Caches
Object ka andar ek Shape hota hai — same order, same Shape, Fast. Delete kiya, Dictionary Mode, Slow.
Every object in V8 has a hidden C++ class called a Map (also known as a Shape or Hidden Class) that describes its structure. The Map tells V8 where properties are stored in memory — their exact offsets, not just their names.
When you add a property, V8 doesn't modify the existing hidden class. It transitions to a NEW hidden class. Objects with the same property structure share the SAME hidden class, making property access incredibly fast and memory efficient.
// Same structure, same Hidden Class (FAST)
const obj1 = {};
obj1.x = 1;
obj1.y = 2;
// V8: Map0 (empty) -> Map1 (x) -> Map2 (x, y)
const obj2 = {};
obj2.x = 3;
obj2.y = 4;
// V8: Reuses Map0 -> Map1 -> Map2! Same shape.
// Different structure, different Hidden Classes (SLOW)
const obj3 = {};
obj3.y = 5; // Map0 -> Map3 (y) -> Map4 (y, x)
obj3.x = 6;
// obj3 has a DIFFERENT hidden class than obj1/obj2!
Inline Caching (IC) is V8's secret weapon for fast property access. When you read obj.x, V8 doesn't search the object every time — it memorizes where it found the property.
The first time obj.x is accessed, V8 notes: "The last time I read 'x', the object had Map2, and 'x' was at offset 0." Next time, V8 checks if the object's Map is still Map2. If yes — it skips the lookup and goes straight to offset 0. Lightning fast.
function getX(obj) {
return obj.x; // V8 remembers the hidden class here
}
// Monomorphic: Always same shape -> IC hits every time
const a = { x: 1, y: 2 };
getX(a); // V8 caches: "Map(x,y) -> offset 0"
getX(a); // Cache HIT! Direct memory access.
// Polymorphic: Two different shapes
const b = { x: 1, y: 2, z: 3 };
getX(b); // V8 updates IC: "Check Map(x,y) OR Map(x,y,z)"
const c = { x: 1, w: 4 };
getX(c); // IC becomes polymorphic (3 shapes). Slower.
// Megamorphic: Too many shapes -> V8 gives up
// If you pass 10 different shaped objects to getX,
// the IC becomes megamorphic and uses slow hash lookup.
These patterns kill V8 optimization silently. Your code still works, but it runs significantly slower.
KILLER 1: Adding properties in different orders. Creates different hidden class transition chains. V8 cannot reuse hidden classes across instances.
KILLER 2: Deleting properties. Forces V8 to transition the object to a slow "dictionary mode" where properties are stored in a hash table.
KILLER 3: Mixing types. If obj.x = 1 (number) then obj.x = "string" — V8 must change the hidden class to accept any type, degrading optimization.
KILLER 4: Dynamic runtime additions. Adding properties after construction instead of in the constructor creates divergent hidden classes.
// KILLER 1: Different order
function PointBad(x, y) {
this.x = x;
this.y = y;
}
const p1 = new PointBad(1, 2); // Map(x, y)
const p2 = new PointBad(1, 2);
p2.z = 3; // Map(x, y, z) -- different class!
// FIX: Consistent initialization
function PointGood(x, y, z) {
this.x = x; // Always same order
this.y = y;
this.z = z || null; // Pre-allocate, set null if unused
}
// KILLER 2: Delete
const user = { name: 'Sai', age: 25, temp: 'xyz' };
delete user.temp; // V8 switches to dictionary mode!
// FIX: Set to null
user.temp = null; // Keeps the hidden class intact!When an object has too many properties added or deleted, or the hidden class transition tree gets too deep, V8 gives up. It converts the object to "Dictionary Mode" (also called "Slow Properties").
In dictionary mode, properties are stored in a hash table instead of fixed memory offsets. Property access changes from O(1) pointer arithmetic to a hash lookup — significantly slower.
This is an irreversible transition. Once an object enters dictionary mode, it never goes back to fast mode.
// Triggering dictionary mode with too many deletes
const obj = {};
for (let i = 0; i < 1000; i++) {
obj['prop' + i] = i;
}
for (let i = 0; i < 500; i++) {
delete obj['prop' + i]; // V8: "Too many deletes! Dict mode."
}
// Now obj is in dictionary mode. Every access is slow.
console.time('fast');
const fastObj = { a: 1, b: 2 };
for (let i = 0; i < 1000000; i++) fastObj.a;
console.timeEnd('fast');
console.time('slow');
for (let i = 0; i < 1000000; i++) obj.prop999; // Dict mode
console.timeEnd('slow'); // Much slower!
--allow-natives-syntax flag, then run %DebugPrint(obj) in the console. If you see elements: DictionaryElements, your object has been de-optimized to dictionary mode.Understanding the difference between fast and slow properties is what separates a senior JavaScript developer from a junior one.
Fast Properties: Stored in fixed memory offsets, described by a Hidden Class. O(1) access. Optimized by V8's TurboFan compiler. This is the default for well-structured objects.
Slow Properties (Dictionary Mode): Stored in a hash table. O(n) access. NOT optimized by TurboFan. Triggered by excessive property deletion or structural changes.
Object.freeze(): Tells V8 the object will never change. V8 can aggressively optimize — even inline property values in compiled code.
// Object literals are FAST (V8 knows the shape immediately)
const user = {
name: 'Sai', // Offset 0
age: 25, // Offset 1
role: 'dev' // Offset 2
}; // One single hidden class created upfront!
// Object.freeze optimization
const config = Object.freeze({
host: 'localhost',
port: 3000
});
// V8 marks this as immutable. TurboFan can inline values!
// The Hidden Class Transition Tree for user:
// Map0 (empty) -> Map1 (name) -> Map2 (name, age) -> Map3 (name, age, role)
// Every object with name, age, role in that order shares Map3.
delete — set to null instead. Keep property types consistent. Use Object.freeze() for truly immutable objects. These habits ensure V8 keeps your objects on the fast path.Lo kar liya — Key Points:
- ✅ V8 uses Hidden Classes (Maps/Shapes) to describe an object's structure, storing property offsets for O(1) access
- ✅ Adding properties in different orders creates different hidden classes, preventing V8 from optimizing
- ✅ Inline Caches (IC) memorize property access patterns; monomorphic (1 shape) is fastest, megamorphic (5+ shapes) is slowest
- ✅ Deleting properties forces V8 into Dictionary Mode (hash table), which is significantly slower than fixed-offset access
- ✅ Use
nullinstead ofdeleteto remove a property without breaking the hidden class - ✅ Initialize all properties in the constructor in the same order to ensure all instances share the same hidden class
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login