# Javascript equality and sameness

This is the second post in my Javascript serial.

There are 3 types of comparison operators in Javascript

`===`

(most recommend): strict comparison or identity comparison`==`

(not recommend): loose comparison`Object.is`

api: SameValue comparison. Added from ES6.

From my practical experience, `===`

is the first comparison you should consider when choosing one from the above three types, as it works in every version of the Javascript implementation.

`==`

is indeed discouraged in default ESlint configuration.

`Object.is`

is added from ES6. You should check compatibility and apply polyfill if your client's browser does not support it.

## What is the difference?

Because `==`

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 `===`

and `Object.is`

is how do they handle these 3 special primitive number values: `+0`

, `-0`

, and `NaN`

.

`+0`

and `-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.

In Javascript, the fact that number is stored in IEEE754 format ( ref) implies that all numbers in Javascript have theirs own 64 bit (i.e. 8 bytes) presentations.

However, this does not mean that all 64-bit binary arrays have their own float value due to the specification of the IEEE754 format. In other words, the map from IEEE754 formatted number (or Javascript number) to 64-bit binary array is injective but not surjective.

Hence, there are many 64-bit binary arrays that do not have an equivalent numerical value. In Javascript, 2 of them are chosen to be `Infinity`

and `-Infinity`

. All other non-associated values are considered not-a-number ( `NaN`

) instances. Thus, there is not only one but many `NaN`

instances.

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, `b2f`

converts `Unit8Array`

instance to a number. Using `f2b`

, we can check for default `NaN`

instance, `Infinity`

and `-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]
```

Throughout the above discussion, we understand that in Javascript, the strict equal `===`

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 `x`

is `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 `NaN`

in Javascript. Via `Object.is(NaN, x)`

or `isNaN(x)`

.

## Quirk

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 `.includes()`

use `Object.is`

comparison, in the contrast of strict equal `===`

comparison used by `.indexOf()`

.

Bonus image from an MDN article

In this post, I have shared my knowledge about equality comparison operators in Javascript. Mostly I discussed the strict comparison and SameValue comparison.

Please feel free to discuss.