JavaScript Object Internals | From Hidden Classes to Hash Maps
Ever wondered what really happens when you write below code in Javascript?
const obj = { a: "Hey", b: 123 };Have you ever considered,
- Whether those keys will be stored on the memory along with their values.
- Whether this is an hash map-like structure?
- Are those values stored in the memory contiguous?
There are lots of questions coming to my mind whenever I stop writing the code and then start thinking how engine can understand what to do, and how those things are stored in the memory :)
I am kind of an overthinking person, so as you can see, it blocks my working routine and push me to start digging into those unknowns instead of building a product hahaha
Anyway, thanks to that, I am learning lots of things whether I need those information or not.
Let's first start with by understanding of the data types in Javascript
Primitives and Objects
Normally, we can store our primitive variables (integers, chars, boolean, etc.) by their values or by their references such as objects, arrays, functions, etc.
It is simpler to understand how things are stored by values for example
const a = 123;When JS Engine sees above code, the flow like that:
- It parses the code into Abstract Syntax Tree (AST)
- It creates a binding in the nearest lexical environment
So internally
LexicalEnvironment: {
"a" → binding pointing to value `123`
}This is not like compiling to a raw memory address (as in C/C++/Rust).
Instead:
"a"is entered into a scope map (symbol table)- That scope map lives in a closure environment record
Where does that value (123) be allocated in the memory?
It stored on the stack or in register, depending on optimizations. The binding for "a" is a reference to that memory location (abstracted by the engine).
Later, when you write console.log(a)
The engine:
- Looks up
ain the lexical environment chain - Finds the binding ➡️ fetches its value ➡️ returns 123
So a is not compiled to a memory address directly like in C, C++ or Rust.
Because Javascript is:
- Dynamic
- Lexically Scoped
- Not statically typed
If V8 (JS Engine) detects that a is a 🔥 hot variable, its optimizing compiler (TurboFan) may "inline the value", and "replace scope lookups with direct memory offsets" (Don't want to dive deep into how JS Engine and Ignition works in that blog).
If we have an idea how primitives are handled by JS Engine and stored, let's dive into how objects are handled.
Are JavaScript Objects Hash Maps?
Most of the people say that Javascript Objects are Hash Maps, but this is not 100% true. JS engines may use hash maps depending on the object's usage patterns. In V8, Dictionary Mode explicitly uses a hash map-like structure for dynamic cases.
Actually, we can say there are two types of modes affecting data structure of JS Objects:
1. Dictionary Mode (Hash map-like structure):
Triggered when:
- You delete a property
- You use computed keys
obj[Math.random()] - You dynamically add keys in unpredictable ways
const obj = {
a: 1,
b: 2,
c: 3,
};
// 1. Deleting a property forces dictionary mode
delete obj.b;
// 2. Adding a property with a computed (non-static) key forces dictionary mode
const dynamicKey = Math.random().toString();
obj[dynamicKey] = 42;
// 3. Adding keys out of order / dynamically forces dictionary mode
obj["z"] = 99;
obj["y"] = 88;2. Fast Mode (HiddenClass + Slots):
- You create an object with fixed properties
- You add properties in a consistent order
- You don't delete properties
const obj = { x: "hey", y: 123 }; // Fast ModeDo we store keys of the Object in Memory?
Yes, we do! BUT, the Dictionary mode and Fast Mode approach that storing keys in differently.
Keys are interned strings (shared memory for repeated strings) and stored either in the descriptor array (Fast Mode) or as part of dictionary entries (Dictionary Mode).
Terms like Hidden Class, Map, and DescriptorArray are specific to Google's V8 JavaScript engine (used in Chrome and Node.js). Other engines like Firefox's SpiderMonkey or Safari's JavaScriptCore implement similar concepts under different names and strategies.
In Dictionary Mode

Each field of the object stored in hash map-like structure. We call that structure as NameDictionary.
How engines behave when they encounter with the code line (obj) like above:
1. Keys are hashed using hash function
hashFunction("x"); // This results a hashed integer like 1263128973
hashFunction("y");2. Computing the index
The key is hashed, and the result is used (often via bitmasking or modulo) to compute the index into an internal array where the {key, value} pair is stored. If that index is occupied, probing is used to find the next available slot.
hashedInteger % table_size = index;3. Dictionary Entry allocation
We call {key, value} as Dictionary Entry in C++, and V8 allocates that in heap like below
struct DictionaryEntry {
Name* key; // Interned String
Object* value; // JS value
PropertyDetails flags;
}Whenever we access obj.a, the V8 engine performs a lookup for the "a" key in the internal hash table.
⚠️ The main drawback of Dictionary Mode
Objects do not share structure. For example, if you create a thousand objects with the same shape, the engine creates a thousand independent internal dictionaries — each storing its own keys, even if they are identical.
This is inefficient compared to Fast Mode, where objects with the same structure can share a single HiddenClass and Descriptor Array, reducing memory usage and improving access speed.
In Fast Mode
We do store keys just once in a Hidden Class (Which is also called as Map in engine context)
A HiddenClass is like a runtime-defined struct layout, and it can be shared among thousands of objects with the same structure!
const obj = { x: 1, y: 2 };
const obj2 = { x: 3, y: 4 };Both obj and obj2 point to the same Map.
- No duplicate keys are stored
- Engine uses pointer + offset arithmetic for access.
struct JSObject {
Map* hidden_class; // at offset 0 - pointer to the Map
void* value_slot0; // offset +8 - value for first prop
void* value_slot1; // offset +16 - value for second prop
}As you can see, above struct holds the values, not the keys. The keys are in the Hidden Class.

There is a Descriptor Array which is a metadata table attached to the HiddenClass (Map) that holds each property name + slot/offset + attributes.
You can think HiddenClass and Descriptor Array like below, behind the scenes V8 engines uses C++ structures to handle with those things
HiddenClass1 = {
descriptor_array: DescriptorArray1,
in_object_slots: 2,
prototype: Object.prototype,
};DescriptorArray1 = [
{
name: "x",
slot_index: 0,
attributes: { writable: true, enumerable: true },
},
{
name: "y",
slot_index: 1,
attributes: { writable: true, enumerable: true },
},
];So, when you want to access obj.x:
The JS engine looks up the property in the Descriptor Array to find the slot index for "x". Based on this slot, it calculates the offset in the JSObject to locate the memory address and retrieve the value.
You can see the flow of the property access in Fast Mode

Fast Mode vs Dictionary Mode: Performance Implications
Dictionary Mode prevents optimizations like inline property access, so it's best avoided when performance matters.
Metaphor: The Fast Lane vs. Dirt Road
Imagine a sports car driving on a well-paved race track— smooth, fast, and predictable. This is Fast Mode.
Now imagine that same car trying to speed through a twisting dirt path full of potholes and surprises. That's Dictionary Mode.
Uses a HiddenClass (aka Map) and a Descriptor Array.
Engine knows:
- Property
xis at slot 0 → offset +8 (Each slot is 8 bytes in Javascript) - Property
yis at slot 1 → offset +16
Access becomes a direct pointer + offset calculation — like C structs.
Dictionary Mode:Each property access becomes:
- Compute hash of key
- Probe hash table
- Check key equality
- Retrieve value
No reuse of structure layouts = no inline cache optimization.
Conclusion
Understanding how JavaScript engines handle objects internally helps us write more performant code. By avoiding operations that trigger Dictionary Mode (like deleting properties or using computed keys unpredictably), we can keep our objects in Fast Mode and benefit from optimizations like shared Hidden Classes and direct memory access.
The key takeaway: JavaScript objects aren't simply hash maps. They're sophisticated data structures that adapt based on usage patterns, balancing flexibility with performance.