Artboard 16light, inspiration, solution, idea, innovation,Google Sheets iconSwift icon
Published at
Updated at
Reading time
3min
This post is part of my Today I learned series in which I share all my web development learnings.

The last few days, I was in Cluj-Napoca where I spoke at the excellent JSHeroes conference and saw a fascinating code snippet in Mathias Bynens' talk "V8 Internals for JS Developers" (the recording is from a different event).

Object.is(-0, +0); // false

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 follow the IEEE Standard for Floating-Point Arithmetic. 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. Understanding how this works may take some time, but the important fact is that one bit (the sign bit) in JavaScript numbers defines if a number is positive or negative. And this definition includes zero! Yes there are negative zeros in JavaScript.

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

My first reaction to discovering negative zeros was that I surely don't have these in my code, but you will be surprised! Round -0.23, and you'll end up with a negative zero. A negative zero likely appears in my (and yours) JavaScript, too.

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

But there's more; compare a positive and negative zero and discover that they're treated equal! 😲

-0 === +0 // true

AbdulFattah Popoola wrote a valuable article on the topic and there is even a section in the "You don't know JavaScript" series on positive and negative zeros going more into more details.

Sidenote: you can differentiate -0 and 0 by using division and the resulting Infinity. Positive and negative Infinity are not equal. But there's a nicer way!

1 / -0 === -Infinity    // true 
1 / 0 === Infinity      // true
-Infinity === Infinity  // false

Object.is – comparing without quirks?

Strict comparison with === didn't catch that the two zeros are not the same. It's one of these JavaScript quirks similar to NaN, that you may know is not equal to itself.

NaN === NaN // false

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

These occasions are when Object.is comes into play. It behaves the same as === in most cases but includes some minor "improvements" that make things a bit more logical.

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

Not everybody is aware of the -0 existence, which means that for the rounding of -0.23 a differentiation between 0 and -0 could lead to hard-to-spot bugs. That's maybe the reason why === ignores it.

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: is Object.is as fast as ===? I created a quick JSPerf to see how Object.is performs in comparison to ===. Object.is seems to be significantly slower than === in Safari and Firefox, whereas it's more or less the same in Chrome. That's very interesting!

If you have comments on the performance test, please let me know. Browser internals are incredibly 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

Related Topics

Related Articles