How do Set and Map compare objects?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
By reference, not by content. Two objects are the same key only if they are literally the same object in memory.
const a = { id: 1 };
const b = { id: 1 };
const set = new Set([a, b]);
set.size; // 2 — different references
set.has({ id: 1 }); // false — a third, unrelated object
set.has(a); // true
The same applies to Map keys. This surprises people who expect Set to deduplicate objects the way it deduplicates numbers and strings.
The comparison used
Internally both use SameValueZero, which behaves like === with one exception: NaN equals itself.
new Set([NaN, NaN]).size; // 1 — unlike ===, which says NaN !== NaN
new Set([0, -0]).size; // 1 — +0 and -0 are treated as the same
Deduplicating objects anyway
Pick a stable key yourself:
// by a natural id
const unique = [...new Map(users.map((u) => [u.id, u])).values()];
// by full content, when no id exists
const seen = new Set();
const unique2 = items.filter((i) => {
const key = JSON.stringify(i);
return seen.has(key) ? false : (seen.add(key), true);
});
JSON.stringify is a blunt instrument — key order matters and functions or undefined disappear — so prefer an explicit id when you have one.
Why reference equality is the right default
Deep comparison would have to walk the whole object on every lookup, turning a constant-time operation into an arbitrarily expensive one, and there is no single correct definition of "equal" for arbitrary objects. Reference identity is fast and unambiguous, and it is exactly what you want when using objects as keys to attach metadata — which is also why WeakMap exists, letting an entry disappear once nothing else references the key.
