How Lodash _.pick Handles Object Memory Allocation
When invoking _.pick in the Lodash JavaScript library,
the engine creates a brand-new object on the heap while copying selected
property descriptors and references from the source object. This article
examines the internal structural memory mapping generated during this
process, focusing on heap allocation, V8 Hidden Classes (Shapes),
reference graph mutations, and memory retention dynamics.
Fresh Heap Allocation and Root Identification
Calling _.pick(source, [paths]) instructs Lodash to
evaluate the specified paths and construct a completely new container
object. Under the hood—typically routing through internal utilities like
basePick or basePickBy—the method allocates an
empty plain object ({}) in the JavaScript runtime’s nursery
space (young generation heap).
This newly generated object receives:
- A unique memory address distinct from the original source.
- Its own identity pointer (
===equality against the source evaluates tofalse). - A standard prototype reference pointing to
Object.prototype.
Hidden Classes and Transition Trees
In engines like V8, objects rely on Hidden Classes (also known as "Shapes" or "Maps") to optimize property access via Inline Caches (ICs).
- Initial Shape: The fresh target object begins with
the root empty object shape (
Map0). - Dynamic Transitions: As
_.pickiterates over the allowed properties and writes them onto the new object, the engine moves along a transition tree:- Adding Property A transitions the object from
Map0toMap1. - Adding Property B transitions it from
Map1toMap2.
- Adding Property A transitions the object from
- Shape Divergence: Because
_.pickdynamically assigns properties at runtime based on the array order of the keys provided, the resulting object may not share the same Hidden Class as an object instantiated with an object literal containing the same keys in a different order. If a large number of dynamic keys are picked inconsistently across invocations, V8 may bypass the transition tree entirely and downgrade the object to "dictionary mode" (slow mode), storing properties in a hash table rather than fixed offset slots.
Pointer Mapping: Shallow Copy Architecture
The structural memory mapping created by _.pick is
strictly shallow. It isolates the top-level container while preserving
internal reference links:
- Primitives: Value types (integers, booleans, small strings) are stored directly in the object’s in-object property slots or as tagged pointers.
- Reference Types: When the picked property is an object, array, or function, the runtime does not duplicate the downstream heap structure. Instead, it copies the 64-bit pointer pointing directly to the preexisting heap address of that nested entity.
Source Object [Address: 0x001]
├── primitive: 42 (Value copy)
└── nestedRef: ──┐
│
Picked Object [Address: 0x002]
└── nestedRef: ──┴──> [Heap Allocation: 0x0A9] (Shared Reference)
As a result, a split reference topology is formed. Mutating a nested reference via the picked object directly mutates the source object's underlying structural data, as both pointers resolve to the exact same offset in memory.
Property Storage: In-Object vs. Backing Store
When _.pick assigns the target properties, V8 determines
where these values physically live relative to the object header:
- In-Object Slots: Allocated directly within the
fixed-size contiguous block reserved for the
JSObject. These offer the fastest access times. - Out-of-Object Properties Array: If the number of picked properties exceeds the pre-allocated in-object capacity, the runtime allocates a secondary heap array (the property backing store) and points the base object toward it.
Garbage Collection and Retainment Implications
The structural memory mapping produced by _.pick
directly impacts Garbage Collection (GC) reachability graphs.
Because references to nested objects are retained within the newly
allocated root, selecting a single deeply nested object or property via
_.pick keeps that entire referenced sub-tree reachable from
the root. If the source object is subsequently set to null
to free memory, any sub-objects referenced by the picked object cannot
be swept by the Mark-and-Sweep garbage collector, preserving their
residency in the heap.