A strong answer
Because JavaScript is dynamically typed, V8 avoids slow hash-table lookups on event.latencyMs by attaching a pointer to a Hidden Class (called a Map or Shape) at byte offset 0 of every heap object. Each time you add a property, V8 follows a transition edge in a Hidden Class tree (Map0 -> Map1(id @ +24) -> Map2(latencyMs @ +32)). At every property read site, V8's JIT (Ignition/Maglev/TurboFan) installs an Inline Cache (IC): (1) Monomorphic IC (1 Shape seen): compares obj.map == ExpectedMap in 1 CPU instruction and loads directly from fixed byte offset +32 (~0.8 ns); (2) Polymorphic IC (2–4 Shapes): branches across up to 4 cached Maps; (3) Megamorphic IC (>4 Shapes) or delete obj.prop: delete detaches the object from the Shape transition tree into slow hash-table Dictionary Mode (~38 ns, ~45x slower!). Similarly, for closures, V8 allocates a single heap Context array per lexical scope shared by all nested functions in that scope—meaning a sibling closure can accidentally keep a 10 MB buffer alive!
Two JavaScript objects share the exact same V8 Hidden Class (Map) if and only if they start from the same prototype/constructor and have the exact same sequence of property names added in the exact same order without executing delete. When every instance returned by a factory function initializes the exact same keys in the exact same order (setting absent optional properties to undefined or null), every instance terminates at the identical leaf Map node, guaranteeing a 1-shape Monomorphic Inline Cache at all downstream read sites.
A Monomorphic IC property load takes ~0.8 ns (1 Map pointer check + 1 fixed-offset memory read), whereas a Megamorphic or Dictionary Mode (delete) lookup takes ~35–45 ns (~45x slower). In production systems (V8 (Node.js, Chrome, Deno, Cloudflare Workers), JavaScriptCore (Structure IDs in Bun and Safari), Fastify's schema compiler, and Pino logger all enforce fixed-shape object construction for monomorphic ICs.), engineers monitor these exact trade-offs to keep p99 latency predictable and prevent resource exhaustion under peak load.
What the interviewer is listening for
- Traces how V8 Hidden Classes (Maps/Shapes), Inline Caches (ICs), and shared lexical closure Contexts operates in memory step by step rather than giving a vague textbook definition.
- States the core correctness invariant and explains why edge cases do not violate it.
- Quantifies time, space, and hardware costs (Monomorphic IC (1 Shape), Polymorphic IC (2–4 Shapes)) with concrete numbers.
- Identifies real-world failure modes (Conditionally adding optional fields (
if (x) obj.x = x)) and explains how production systems mitigate them.
Common mistakes
- Treating V8 Hidden Classes (Maps/Shapes), Inline Caches (ICs), and shared lexical closure Contexts as a black box without explaining the underlying memory or state transitions.
- Ignoring worst-case tail latency or memory overhead (Using plain objects
{}as dynamic hash maps with arbitrary user-supplied keys (cache[userId] = val; delete cache[oldId])). - Forgetting boundary conditions and error recovery (Capturing a huge request object inside a lexical scope that also creates a long-lived callback).