Lodash Getter Conflict Resolution Rules
This article provides an overview of how the Lodash library handles
property conflicts when merging objects containing identically named
getters. In JavaScript, accessor properties behave differently than
standard data properties during object manipulation. Understanding
Lodash's internal mechanics—specifically how functions like
_.merge evaluate getters, prioritize source values, and
assign data—is essential for avoiding silent assignment failures,
runtime errors, and unexpected mutations.
Getter Evaluation Over Descriptor Copying
Lodash does not copy property descriptors when merging objects.
Functions like _.merge and _.assign iterate
through properties using standard property access
(source[key]). Consequently, when Lodash encounters a
getter on a source object, it immediately invokes the getter function
and retrieves the returned value. The merge operation proceeds using
this evaluated value rather than transferring the getter's accessor
definition to the target object.
The Rightmost Source Precedence Rule
When multiple source objects define identically named getters, Lodash applies a strict "last-write-wins" resolution sequence from left to right:
- Lodash evaluates the getter on the first source object.
- It then evaluates the identically named getter on the subsequent source object.
- The value retrieved from the rightmost source supersedes any evaluated values from earlier sources.
The intermediate getter values are evaluated in order, but only the final evaluated value participates in the assignment to the target object.
Assignment Semantics and Target Setter Invocation
Lodash uses standard property assignment
(object[key] = value) rather than
Object.defineProperty() when writing merged values to the
target object. This creates specific conflict behaviors depending on the
target's existing structure:
- Target Has a Getter and Setter: If the target object possesses an existing accessor with both a getter and a setter, assigning the evaluated source value triggers the target's setter method. The setter dictates how the incoming value is applied.
- Target Has a Getter-Only (Read-Only Accessor): If
the target contains an identically named getter without a corresponding
setter, standard assignment fails. In strict mode
(
"use strict"), this throws aTypeError: Cannot set property ... which has only a getter. In non-strict environments, the operation fails silently without updating the target.
Type-Based Merge vs. Replacement Rules
Once a getter's return value is extracted, conflict resolution follows Lodash’s standard merge rules against the existing target value:
- Plain Objects and Arrays: If the getter resolves to a plain object or array, and the target property is also an object or array, Lodash recursively merges the nested properties rather than replacing the target outright.
- Primitives and Other Types: If the getter resolves
to a primitive value, function, or non-plain object (such as a
DateorRegExp), it replaces the target value completely. undefinedValues: If a getter explicitly returnsundefined, Lodash does not overwrite an existing target value. An explicitundefinedfrom a source getter leaves the target's current value intact unless specified otherwise via custom customizers like_.mergeWith.
Customizing Resolution
with _.mergeWith
Because standard Lodash operations discard accessor descriptors,
projects requiring the preservation of getters or custom override
strategies must use _.mergeWith. By providing a customizer
function, developers can inspect
Object.getOwnPropertyDescriptor() on source objects and
selectively redefine descriptors using
Object.defineProperty() rather than relying on default
getter invocation and assignment.