How Lodash Handles Conflicting Getters in Merges
When merging objects with identically named getters, the Lodash library resolves conflicts by evaluating the getters into static values and applying a last-write-wins strategy. Rather than transferring the underlying getter functions or property descriptors, Lodash executes them during traversal, merges the returned data, and assigns the final evaluated result as a standard value property on the destination object.
Immediate Getter Invocation
When _.merge processes source objects, it accesses
properties using standard property lookup rather than inspecting
property descriptors via Object.getOwnPropertyDescriptor.
This means that as soon as Lodash reads a property backed by a getter,
JavaScript invokes the getter function immediately. Lodash receives only
the returned value of the getter, entirely unaware that the property was
originally an accessor.
Precedence and Conflict Resolution
When multiple source objects define a getter with the same key, Lodash processes them sequentially from left to right:
- Primitive Values: If the getters evaluate to primitive values (such as strings, numbers, or booleans), the value from the rightmost source object overwrites any previous value.
- Object Values: If the getters evaluate to plain JavaScript objects, Lodash does not simply overwrite the property. Instead, it recursively descends into the returned objects, merging their child properties together according to the same rules.
- Type Clashes: If an earlier getter returns an object and a later getter returns a primitive (or vice versa), the later value completely replaces the earlier value, halting recursion.
Loss of Accessor Descriptors
Because Lodash copies evaluated values rather than property descriptors, the target object loses the dynamic nature of the original getters. After the merge is complete, the resulting property becomes a standard, writable, and configurable data property containing the final merged value. Any subsequent state changes that would have altered the original getter's return value will no longer reflect on the merged object.
Custom Conflict
Resolution with _.mergeWith
If default evaluation or overwriting behavior is undesirable, Lodash
provides the _.mergeWith method. This function accepts a
customizer callback that exposes the target value, source value,
property key, and parent objects:
const _ = require('lodash');
const objA = {
get value() { return { a: 1 }; }
};
const objB = {
get value() { return { b: 2 }; }
};
const result = _.mergeWith({}, objA, objB, (objValue, srcValue, key) => {
// Custom logic to handle specific keys or retain descriptors
if (key === 'value') {
return Object.assign({}, objValue, srcValue);
}
});Using _.mergeWith allows developers to intercept the
conflict and determine whether to combine, prioritize, or conditionally
preserve values before Lodash applies its default recursive
assignment.