TIL: +-0, NaN and Object.is in JavaScript
Tags: javascript
Published: 2018-05-22 19:44:19

---
title: TIL: +-0, NaN and Object.is in JavaScript
published: true
tags: javascript
canonical_url: https://www.stefanjudis.com/today-i-learned/0-nan-and-object-is-in-javascript/
---

The last few days I was in [Cluj-Napoca](https://en.wikipedia.org/wiki/Cluj-Napoca) where I spoke at the excellent [JSHeroes conference](https://jsheroes.io/). In the talk ["V8 Internals for JS Developers"](https://www.youtube.com/watch?v=HULaOA5oJMY) (the recording is from a different event though) of [Mathias Bynens](https://twitter.com/mathias) I saw a very interesting code snippet.

```javascript
Object.is(-0, +0);
```

This single line is fascinating in two ways – let's have a look at it.

## The two existent zeros in JavaScript

The first fact is that numbers in JavaScript are following [the IEEE Standard for Floating-Point Arithmetic](https://en.wikipedia.org/wiki/IEEE_754). This standard is available in several variants, and JavaScript uses "Double precision" also called "binary64" based on 64 bits.

IEEE 754 defines that [a sign, a significant, and an exponent to describe each finite number](https://en.wikipedia.org/wiki/IEEE_754#Formats). To understand how this works it may take some time but the important fact is that there is one bit (the sign bit) in JavaScript numbers which defines if a number is positive or negative which means that `0` can be negative, too.

```javascript
const posNumber = 1;
const negNumber = -1;
const posZero = +0;
const negZero = -0;
```

My first reaction to the discovery of negative zeros was that I surely don't have these in my code, but well... when I round `-0.23` I'll end up with a negative zero as well which makes it more likely that a negative zero appears in my JavaScript, too.

```javascript
Math.round(-0.23); // -0
```

It becomes interesting when you want to compare positive and negative zeros though because they're treated the same.

```javascript
-0 === +0 // true
```

[AbdulFattah Popoola](https://twitter.com/abdulapopoola) wrote [a nice article](https://abdulapopoola.com/2016/12/19/why-javascript-has-two-zeros-0-and-0/) and there is even [a section in the "You don't know JavaScript" series](https://github.com/getify/You-Dont-Know-JS/blob/master/types%20%26%20grammar/ch2.md#zeros) on positive and negative zeros going more into more details if you're interested.

*Sidenote: you can differentiate `-0` and `0` using division and the resulting `Infinity`.*

```javascript
1 / -0 === -Infinity    // true 
1 / 0 === Infinity      // true
-Infinity !== Infinity  // true
```

## Object.is – comparing without quirks?

So, the strict comparison with `===` didn't catch the fact that the two zeros are not the same. You may know that `NaN` is also not equal to `NaN` either.

```javascript
NaN === NaN // false

// you can use Number.isNaN as an alternative
Number.isNaN(NaN) // true
```

These occasions are when `Object.is` could come into play. In most cases, it behaves the same as `===` but it includes some minor "improvements" which make things a bit more logical.

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

The downside of this is that not everybody is aware of the existence of `-0` which means that for the rounding of `-0.23` a differentiation between `0` and `-0` __could lead to hard to spot bugs__. That's probably why it's usually ignored in JavaScript. 

I saw `Object.is` for the first time in Mathias' slides and it doesn't seem to be used that often.

One question that came to mind immediately was if it `Object.is` is as fast as `===`. I created [a quick JSPerf](https://jsperf.com/vs-objet-ist) to see how `Object.is` performs in comparison to `===`. In Safari and Firefox `Object.is` seems to be significantly slower than `===` whereas in Chrome it's more or less the same. That's very interesting!

If anyone has any comments on the performance test, please let me know. Browser internals are extremely complicated, and sometimes an optimization takes place in a test which then invalidates the whole thing. 

I'd also love to hear if you use `Object.is` in your source code! :)


### Additional resources

- [How numbers are encoded in JavaScript](http://2ality.com/2012/04/number-encoding.html)
- ["Numbers" chapter in "Speaking JavaScript](http://speakingjs.com/es5/ch11.html#two_zeros)
- [Why JavaScript has two zeros: -0 and +0](https://abdulapopoola.com/2016/12/19/why-javascript-has-two-zeros-0-and-0/)
- [Object.is on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)