Lodash assign Overwrite Priority for Complex Keys

This article examines how Lodash’s _.assign method resolves key collisions when combining JavaScript objects with overlapping and complex properties. You will learn the strict left-to-right evaluation order used by the method, how shallow assignment fundamentally impacts nested objects and arrays, and how _.assign differs from recursive merging alternatives like _.merge.

The Left-to-Right Precedence Rule

Lodash’s _.assign function applies own enumerable string-keyed properties from one or more source objects onto a target object. The syntax is structured as:

_.assign(destination, [sources])

When resolving key collisions, _.assign adheres strictly to a left-to-right evaluation order. The destination object serves as the baseline, and each subsequent source object provided in the argument list processes sequentially:

  1. Properties from source1 overwrite properties with identical names in the destination object.
  2. Properties from source2 overwrite properties from both destination and source1.
  3. This sequence continues until the final source argument has been processed.

The destination object is directly mutated in-place and returned as the final result.

Shallow Assignment and Complex Overlapping Keys

The most critical architectural detail of _.assign regarding complex data structures (such as nested objects and arrays) is that it performs shallow copying, not deep recursive merging.

When an overlapping key contains a complex object, _.assign does not inspect or reconcile the inner properties of that object. Instead, the reference from the right-most source completely replaces whatever existed at that key previously.

Example: Nested Object Replacement

const destination = {
  config: {
    debug: true,
    timeout: 1000
  }
};

const source = {
  config: {
    timeout: 5000,
    retries: 3
  }
};

_.assign(destination, source);

Resulting destination:

{
  config: {
    timeout: 5000,
    retries: 3
  }
}

In this case, destination.config.debug is not preserved. Because _.assign is strictly a shallow operation, the entire config object reference in source completely overwrites the config object in destination.

Overwrite Behavior with undefined Values

Unlike _.defaults or _.mergeWith (when customized), _.assign treats explicit undefined values as valid assignments:

const destination = { environment: 'production' };
const source = { environment: undefined };

_.assign(destination, source);
// destination.environment is now undefined

If an overlapping key exists on a later source object and its value is explicitly set to undefined, it will successfully overwrite the defined value present in earlier objects.

_.assign vs. _.merge for Complex Keys

To achieve deep recursive property preservation rather than wholesale overwriting: