===(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 about the loose comparison operator here.
The main difference between
Object.is is how do they handle these 3 special primitive number values:
-0 have same mathematical semantic meaning and they are same in most of mathematical operations. However, in fact, they are different values and have different byte presentations.
With strict comparison
+0 equals to
-0, in vice versa,
NaN is not equal to itself (
0 is interpreted as
+0). While these comparisons' result are both reversed with
Object.is comparison. Check ECMS ( strict equality, SameValue ) specification for reference.
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 you to read the reference to understand my following content in this paragraph.
-Infinity. All other non-associated values are consider not-a-number (
NaN) instances. Thus, there is not only one but many
I could not found whether ECMA specification defines these special number values' binary presentation from the specs. Thus, I consider the binary presentation varies from implementation to implementation.
Use this script from MDN docs to check for binary presentation of an arbitrary number.
var f2b = x => new Uint8Array(new Float64Array([x]).buffer); var b2f = x => new Float64Array(x.buffer);
f2b converts number value to 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 operation.
=== 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' result 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 a MDN article
Please feel free to discuss.