===(most recommend): strict comparison or identity comparison
==(not recommend): loose comparison
Object.isapi: SameValue comparison. Added from ES6.
From my practical experience,
== is indeed discouraged in default ESlint configuration.
What is the difference?
== is not so useful and it will raise my eslint warning when being used. I have never used or seen any use case of the loose comparison
== operator in real life. Thus, I will not discuss the loose comparison operator here.
The main difference between
Object.is is how do they handle these 3 special primitive number values:
-0 have the same mathematical semantic meaning and they are the same in most mathematical operations. However, in fact, they are different values and have different byte presentations.
With strict comparison
+0 equals to
-0, vice versa.
NaN is not equal to itself (
0 is interpreted as
+0). While these comparisons' results are both reversed with
Object.is comparison. Check ECMS ( strict equality, SameValue ) specification for reference.
0 === -0 // true Object.is(0, -0) // false 1 / 0 // Infinity 1 / -0 // -Infinity NaN === NaN // false Object.is(NaN, NaN) // true
Why +0, -0, and NaN?
To understand this specification, you should have a look at double-precision binary floating-point format binary64. It is not required for you to read the reference to understand the following content in this paragraph.
-Infinity. All other non-associated values are considered not-a-number (
NaN) instances. Thus, there is not only one but many
I could not find whether the ECMA specification defines these special number values' binary presentation from the specs. It is probably that the binary presentation varies from implementation to implementation.
Use this script to check for the binary presentation of an arbitrary number.
f2b converts number value to an 8-length byte array,
Unit8Array instance to a number. Using
f2b, we can check for default
-Infinity binary representations.
f2b(NaN) //Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 127] f2b(Infinity) //Uint8Array(8) [0, 0, 0, 0, 0, 0, 240, 127] f2b(+Infinity) //Uint8Array(8) [0, 0, 0, 0, 0, 0, 240, 127] f2b(-Infinity) //Uint8Array(8) [0, 0, 0, 0, 0, 0, 240, 255] f2b(0) //[0, 0, 0, 0, 0, 0, 0, 0] f2b(+0) //[0, 0, 0, 0, 0, 0, 0, 0] f2b(-0) //[0, 0, 0, 0, 0, 0, 0, 128]
=== operators give understandable and common sense operations.
=== considers all values are different from
NaN even the
NaN itself. And the only case in which
x !== x is
true is when
NaN, in a sense that we do not know which instance the
NaN value is.
There are 2 ways to check if a value is
Object.is(NaN, x) or
Check these expressions' results from your browser. This quirk requires your browser to support ES6 Array.prototype.includes().
let x = 'hello' [x].includes(x) // true [x].indexOf(x) // 0 x = NaN [x].includes(x) // true [x].indexOf(x) // -1
The result can be explained by the fact that
Object.is comparison, in the contrast of strict equal
=== comparison used by
Bonus image from an MDN article
Please feel free to discuss.