ESC

Type to search the knowledge base.

Object.is vs ===

Object.is vs === for NaN and ±0 — SameValue vs Strict Equality, and when each shows up in real checks.

beginner3 min read
  • javascript
  • object-is

Most of the time === is what you want. Object.is implements the SameValue algorithm — almost ===, except two cases people trip on: NaN and signed zero.

NaN === NaN;           // false
Object.is(NaN, NaN);   // true

+0 === -0;             // true
Object.is(+0, -0);     // false

Side-by-side

A B === Object.is
1 1 true true
'a' 'a' true true
{} {} false false
NaN NaN false true
+0 -0 true false
null undefined false false

No coercion. Both are strict about types.

Why NaN === NaN is false

IEEE 754 and the language define NaN as unordered / not equal to anything, including itself. That breaks naive “did this fail?” checks:

const x = 0 / 0;
if (x === NaN) { /* never */ }
if (Number.isNaN(x)) { /* yes */ }
if (Object.is(x, NaN)) { /* yes */ }

Prefer Number.isNaN for “is this NaN?” — it doesn’t coerce (unlike global isNaN('foo')).

When Object.is matters

  • Maps / Sets / React style “same value” for dependency comparison edge cases
  • Implementing polyfills that match spec SameValue
  • Distinguishing +0 and -0 (rare: some math / canvas / divide-by-zero sign)
1 / +0; // Infinity
1 / -0; // -Infinity
Object.is(1 / +0, 1 / -0); // false

Day-to-day app code: === + Number.isNaN covers almost everything.

SameValueZero (Maps and Sets)

Map/Set key equality uses SameValueZero: like Object.is but +0 and -0 are equal, and NaN equals NaN.

const s = new Set([NaN, +0]);
s.has(NaN); // true
s.has(-0);  // true — SameValueZero
s.size;     // 2 if you also add something else… Set([NaN,+0,-0]) size 2

Know the three names:

  1. Strict Equality (===)
  2. SameValue (Object.is)
  3. SameValueZero (Map/Set keys)

Interview answer (out loud)

“Object.is is like === except Object.is(NaN, NaN) is true and Object.is(+0, -0) is false. I still use === daily and Number.isNaN for NaN checks. Map and Set use SameValueZero, where NaN matches NaN and zeros are not distinguished.”

Implementing polyfills carefully

function objectIs(a, b) {
  if (a === b) {
    // true for +0/-0 together — fix zeros
    return a !== 0 || 1 / a === 1 / b;
  }
  // false for NaN===NaN — fix NaN
  return a !== a && b !== b;
}

This is the classic polyfill shape — good whiteboard material.

React dependency arrays

React’s Object.is comparison for hooks deps means NaN dependencies won’t retrigger forever the way === might suggest, and +0/-0 are distinguished. Rare in UI state; know it exists when debugging pathological numeric state.

Don’t switch the whole codebase to Object.is

Readability and convention matter: === is the lingua franca. Use Object.is when the NaN or signed-zero distinction is the bug you’re fixing.

Further reading

Related guides