Lodash _.xor Behavior with Structural References
This article examines how Lodash’s _.xor function
handles arrays containing structurally identical objects and references.
By default, _.xor determines symmetric differences using
shallow reference comparisons (SameValueZero), meaning that
objects with identical keys and values will not be treated as duplicates
unless they share the exact same memory reference. Understanding this
distinction is critical for developers expecting deep equality checks
during array transformations.
Reference Equality vs. Structural Equality
Lodash’s _.xor creates an array of unique values that is
the symmetric difference of the provided arrays. It filters out elements
that appear across multiple arrays. However, its internal uniqueness and
difference operations rely on SameValueZero comparison
rather than deep structural inspection.
When arrays contain non-primitive types—such as objects or nested
arrays—_.xor evaluates whether the items point to the same
location in memory.
Identical Structural Values with Different References
If two objects have identical properties and values but are
instantiated separately, _.xor views them as distinct
values. Consequently, both objects will appear in the output array.
const objA = { id: 1 };
const objB = { id: 1 };
const result = _.xor([objA], [objB]);
// result: [{ id: 1 }, { id: 1 }]Because objA !== objB, neither object is canceled out
during the symmetric difference calculation.
Shared Object References
When two arrays contain a reference to the exact same object in
memory, _.xor recognizes them as identical. In this
scenario, the shared element is excluded from the returned symmetric
difference.
const sharedObj = { id: 1 };
const array1 = [sharedObj, { id: 2 }];
const array2 = [sharedObj, { id: 3 }];
const result = _.xor(array1, array2);
// result: [{ id: 2 }, { id: 3 }]Here, sharedObj is omitted from the final array because
its reference exists in both input sets.
Achieving Deep Structural Difference with _.xorWith
To compare objects based on their properties rather than their
reference identity, use _.xorWith along with Lodash’s deep
equality comparator, _.isEqual.
const objA = { id: 1, name: 'Alpha' };
const objB = { id: 1, name: 'Alpha' };
const result = _.xorWith([objA], [objB], _.isEqual);
// result: []By passing _.isEqual as the comparator, Lodash evaluates
structural contents recursively, ensuring that distinct references with
identical data cancel each other out as expected.