Object.is()

Not a deep-equality helper, despite the name. It compares exactly what === compares, differing on precisely two pairs of values.

Object static methodES2015Live demo
Common call
Object.is(a, b)
Returns
boolean
Replaces
Number.isNaN checks, and 1/x sign tests for -0
Watch out
it does NOT compare objects structurally
Object.is(aa — First value. Objects are compared by reference, exactly as with ===.type: any · required, bb — Second value.type: any · required)
→ boolean

Demo

Live evaluation
Try:
Inputs
aanyfirst value
banysecond value
Output
Object.is(1, 1)
true

Every case here behaves exactly as === would, which is the honest headline: for ordinary values the two are identical, and === is shorter. The two differences that justify this method cannot be entered through a text box at all. Object.is(NaN, NaN) is TRUE where NaN === NaN is false, and Object.is(0, -0) is FALSE where 0 === -0 is true — but neither NaN nor negative zero survives being typed and parsed as text. Both are shown in the examples below, run against a real runtime.

Parameters

NameTypeRequiredDescription
aanyyesFirst value. Objects are compared by reference, exactly as with ===.
banyyesSecond value.

Return value

boolean — True if the two values are the SameValue. Identical to === except for NaN, which equals itself here, and 0 versus -0, which do not.

Common patterns

Detect NaN in a comparison
Where === always fails.
if (Object.is(value, NaN)) { }
Distinguish -0 from 0
The only concise way.
const isNegZero = Object.is(x, -0);
Use === for everything else
Shorter, and identical in every other case.
if (a === b) { }

Examples

1. NaN equals itself
Object.is(NaN, NaN)
Returns
true
2. === disagrees
NaN === NaN
Returns
false
3. 0 is not -0
Object.is(0, -0)
Returns
false
4. === disagrees again
0 === -0
Returns
true
5. Objects by reference
Object.is({}, {})
Returns
false
6. Same reference
const o = {}; Object.is(o, o)
Returns
true

Pitfalls

1. It does not compare objects structurally
The name suggests a deep "is this the same thing", and it is nothing of the sort. Two objects with identical contents are different values, so this returns false — exactly like ===.
Not structural
Object.is({a: 1}, {a: 1})
false
Compare contents
JSON.stringify(a) === JSON.stringify(b)
true, with caveats
2. The -0 difference can surprise a memo comparison
React and similar libraries use Object.is for their equality checks. A value that flips between 0 and -0 — easy to produce with multiplication or rounding — therefore counts as CHANGED and triggers a re-render, where === would have seen no change.
Counts as different
Object.is(0, -1 * 0)
false
Normalise it
Object.is(0, (-1 * 0) + 0)
true
3. It is not the loose == either
No type coercion happens at all. A string and a number that == would call equal are simply different values here, which is the correct behaviour and worth stating because the method name says nothing about types.
No coercion
Object.is(1, '1')
false
Convert first
Object.is(1, Number('1'))
true
4. Number.isNaN is clearer for the NaN case
If you are testing one value for NaN rather than comparing two, the dedicated predicate says so directly. Object.is earns its place when you need one comparison that handles every value uniformly.
Roundabout
Object.is(x, NaN)
works
Direct
Number.isNaN(x)
clearer

When to use

Use it
  • A comparison that must treat NaN as equal to NaN
  • Distinguishing -0 from 0
  • Implementing a general-purpose equality check over values of any type
  • Matching the semantics libraries use for change detection
Reach for something else
  • Ordinary comparison → ===, which is shorter and identical here
  • Testing a single value for NaN → Number.isNaN
  • Comparing object contents → a deep-equality function
  • You want type coercion → == , though generally do not

Notes

Complexity
O(1)
Return
A boolean; nothing is allocated
CPython impl
V8: Builtins-object-is / SameValue
Memory
No allocation
Thread-safe
Single-threaded; values are only read

FAQ

In exactly two cases, and no others. NaN is equal to itself here and not under ===; 0 and -0 are different here and equal under ===. For every other pair of values the two agree, which is why === remains the right default.

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

History

ES2015
Object.is added, exposing the internal SameValue algorithm the specification already used.