Object.is()
Compares two values for same-value equality, treating NaN as equal and +0 as distinct from -0.
Object.is(value1, value2)- Added in JavaScript ES2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$value1 | any | The first value to compare. |
$value2 | any | The second value to compare. |
Return value
booleantrue if the two arguments are the same value, otherwise false.
Object.is() implements the SameValue algorithm. It behaves exactly like === except in two places:
| Comparison | == | === | Object.is() |
|---|---|---|---|
NaN, NaN | false | false | true |
0, -0 | true | true | false |
'1', 1 | true | false | false |
When to reach for it
- Writing a generic equality helper, a memoisation cache or a change detector where
NaNis a legitimate value and must compare equal to itself. - Numerical code where the sign of zero carries meaning —
-0and0differ in1 / xand in atan2-style geometry.
What trips people up
Object.is() does not do structural comparison. Two objects are the same only if they are the same reference, so Object.is([], []) is false just as [] === [] is. The name suggests deep equality to newcomers; it offers none.
It is also not the same as Array.prototype.includes()' comparison, which uses SameValueZero: includes() finds NaN but treats 0 and -0 as equal, while Object.is() separates them.
Example
When to use it
- Detect NaN in a value without the coercion quirks of the global isNaN()
- Skip a re-render or a cache write when the new value is genuinely identical to the old one
- Assert that a math routine returned -0 rather than 0
Frequently asked questions
What is the difference between Object.is and ===?
They agree on everything except two cases: Object.is(NaN, NaN) is true where === is false, and Object.is(0, -0) is false where === is true.
Does Object.is compare objects deeply?
No. It compares object references, so Object.is({}, {}) is false; use a deep-equal helper or compare serialised forms for structural comparison.
Should I use Object.is instead of === everywhere?
No. === is clearer and faster for ordinary code; reach for Object.is() only when NaN or the sign of zero must be handled correctly.
More examples
A change detector that survives NaN
With !==, a stored NaN always looks different from an incoming NaN, so a UI would re-render forever. Object.is() reports no change, while still flagging the sign flip from 0 to -0 that some numeric code cares about.
function changed(prev, next) {
return !Object.is(prev, next);
}
let state = NaN;
console.log(changed(state, NaN)); // false — nothing to update
console.log(state !== NaN); // true — the naive check misfires
console.log(changed(5, 5)); // false
console.log(changed(5, 6)); // true
console.log(changed(0, -0)); // true — sign flip countsThree flavours of equality on the same data
indexOf() uses strict equality and cannot find NaN at all. includes() and Set use SameValueZero, which finds NaN but folds -0 into 0. Only Object.is() keeps both distinctions, which is why it is the one to use when the sign of zero matters.
const values = [NaN, 0, -0];
console.log(values.indexOf(NaN)); // -1 (uses ===)
console.log(values.includes(NaN)); // true (SameValueZero)
console.log(values.findIndex((v) => Object.is(v, -0))); // 2 (SameValue)
console.log(new Set([0, -0]).size); // 1 — SameValueZero merges them
console.log(Object.is(0, -0)); // false — SameValue does not
Discussion