Q123: Equality, Identity and Object Comparison
What Interviewers Want To Evaluate
This question checks whether you understand JavaScript comparison rules and why equality bugs happen. Interviewers want ==, ===, Object.is, reference identity, NaN, -0, deep equality, shallow equality, React dependency comparisons, and safe comparison strategy.
Senior answers should connect equality to memoization, rendering, state updates, and API data.
Short Interview Answer
JavaScript has several comparison models. === checks strict equality without most type coercion, but NaN !== NaN and 0 === -0. Object.is is similar but treats NaN as equal to itself and distinguishes 0 from -0. Objects are compared by reference identity, not structure. Deep equality compares nested values but can be expensive and tricky. In production code, prefer strict equality, stable identifiers, normalized data, and targeted shallow comparison where possible.
Detailed Interview Answer
Equality sounds small, but it affects correctness and performance.
The common operators are:
== loose equality with coercion
=== strict equality
Object.is same-value comparison
Most application code should default to ===.
Loose Equality
Loose equality performs type coercion.
0 == false; // true
"1" == 1; // true
null == undefined; // true
These rules are hard to remember and can create surprising bugs.
Use loose equality only when the coercion is deliberate and clearly understood.
Strict Equality
Strict equality avoids most coercion.
0 === false; // false
"1" === 1; // false
null === undefined; // false
This is usually the right default.
NaN and -0
Strict equality has special cases.
NaN === NaN; // false
0 === -0; // true
Number.isNaN checks NaN safely.
Number.isNaN(NaN); // true
Object.is
Object.is uses same-value comparison.
Object.is(NaN, NaN); // true
Object.is(0, -0); // false
React uses Object.is style comparison in several state and dependency checks.
Reference Identity
Objects are compared by reference.
{} === {}; // false
const user = {};
user === user; // true
Two objects with identical content are not equal unless they are the same object reference.
Shallow Equality
Shallow equality compares top-level properties.
function shallowEqual(a, b) {
if (Object.is(a, b)) {
return true;
}
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) {
return false;
}
return aKeys.every((key) => Object.is(a[key], b[key]));
}
This is common in UI optimization because it is cheaper than deep comparison.
Deep Equality
Deep equality recursively compares nested structures.
It sounds simple, but real deep equality must consider:
arrays
objects
dates
maps
sets
cycles
symbols
property descriptors
prototypes
custom classes
performance limits
Do not casually write a deep equality function for production without defining scope.
Stable IDs
For domain data, compare stable identifiers instead of whole objects.
selectedUser.id === candidateUser.id;
This is clearer and cheaper than deep comparing user objects.
React Connection
React dependency arrays compare values by identity.
useEffect(() => {
syncFilters(filters);
}, [filters]);
If filters is recreated on every render, the effect runs every time.
Stable object creation, memoization, and normalized state help avoid unnecessary work.
Mutation Problem
Mutation can hide changes from shallow comparison.
state.user.name = "Meera";
setState(state);
The object reference did not change, so systems depending on identity may not detect the update.
Immutable updates create a new reference for changed paths.
Common Mistakes
A common mistake is using JSON.stringify(a) === JSON.stringify(b) for equality. It can fail with property order, unsupported values, dates, functions, cycles, and performance.
Another mistake is deep comparing large values every render to compensate for unstable state design.
Senior Trade-Offs
Choose the comparison model intentionally.
primitive value: strict equality
NaN-sensitive value: Object.is or Number.isNaN
domain object: stable ID
UI optimization: shallow equality with immutable data
rare nested comparison: scoped deep equality
The best comparison is often the one your data model makes unnecessary.
Code or Design Example
function hasSelectionChanged(previous, next) {
return previous.selectedUserId !== next.selectedUserId;
}
This is better than comparing entire selected user objects.
Debugging Workflow
When equality bugs appear:
check strict vs loose equality
check NaN or -0 edge cases
check object reference identity
check mutation hiding changes
check recreated objects causing false changes
check React dependency arrays
compare IDs instead of full objects
avoid generic deep equality in hot paths
Interview Framing
Start with ==, ===, and Object.is. Then explain reference identity and why UI systems rely on immutable references.
Revision Notes
Objects compare by identity. Strict equality is the default. Deep equality is expensive and must be scoped carefully.
Key Takeaways
Equality is a data modeling issue. Stable IDs and immutable updates make comparison simpler and safer.
Follow-Up Questions
- What does
==do? - Why is
===usually preferred? - How does
Object.isdiffer from===? - Why is
NaN === NaNfalse? - How are objects compared?
- What is shallow equality?
- Why is deep equality hard?
- How does React compare dependency values?
- Why does mutation break shallow comparison?
- When should you compare IDs?
How I Would Answer This In A Real Interview
I would say strict equality is the default, mention Object.is for NaN and -0, and explain that objects compare by reference. Then I would connect equality to React dependencies, memoization, immutable updates, and stable IDs.