+-0, NaN a Object.is v JavaScriptu

Posledních pár dní jsem byl v Cluj-Napoca, kde jsem mluvil na vynikající konferenci JSHeroes a viděl jsem fascinující úryvek kódu v přednášce Mathiase Bynense „V8 Internals for JS Developers“ (záznam je z jiné akce).

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

Tato jediná řada je fascinující dvěma způsoby – pojďme se na ni podívat.

Dvě existující nuly v JavaScriptu

Prvním faktem je, že čísla v JavaScriptu se řídí standardem IEEE pro aritmetiku s plovoucí desetinnou čárkou. Tento standard je dostupný v několika variantách a JavaScript používá "dvojitou přesnost" (také nazývanou "binary64") založenou na 64 bitech.

IEEE 754 definuje, že znaménko, signifikantní a exponent popisující každé konečné číslo. Pochopení toho, jak to funguje, může nějakou dobu trvat, ale důležitým faktem je, že jeden bit (znakový bit) v číslech JavaScriptu určuje, zda je číslo kladné nebo záporné. A tato definice zahrnuje nulu! Ano, v JavaScriptu jsou záporné nuly.

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

Moje první reakce na objevení záporných nul byla, že je ve svém kódu určitě nemám, ale budete překvapeni! Kolo -0.23 a skončíte se zápornou nulou. Záporná nula se pravděpodobně objeví i v mém (a vašem) JavaScriptu.

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

Ale je toho víc; porovnejte kladnou a zápornou nulu a zjistěte, že se s nimi zachází stejně! 😲

-0 === +0 // true

AbdulFattah Popoola napsal na toto téma cenný článek a v sérii „Neznáte JavaScript“ je dokonce sekce o kladných a záporných nulách, která jde více do podrobností.

Vedlejší poznámka:můžete rozlišit -0 a 0 pomocí dělení a výsledného Infinity . Kladné a záporné Infinity nejsou si rovni. Ale existuje hezčí způsob!

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

Object.is – porovnání bez výstředností?

Přísné srovnání s === nepochopil jsem, že ty dvě nuly nejsou stejné. Je to jedna z těchto zvláštností JavaScriptu podobná NaN , o kterém možná víte, že se sám sobě nerovná.

NaN === NaN // false

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

Tyto případy jsou, když Object.is přichází do hry. Chová se stejně jako === ve většině případů ale obsahuje některá drobná „vylepšení“, díky kterým jsou věci o něco logičtější.

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

Ne každý si je vědom -0 existence, což znamená, že pro zaokrouhlení -0.23 rozdíl mezi 0 a -0 může vést k těžko odhalitelným chybám . To je možná důvod, proč === ignoruje.

Viděl jsem Object.is poprvé v Mathiasových snímcích a nezdá se, že by se používal tak často.

Jedna otázka, která mě okamžitě napadla:je Object.is tak rychle jako === ? Vytvořil jsem rychlý JSPerf, abych viděl, jak Object.is funguje ve srovnání s === . Object.is se zdá být výrazně pomalejší než === v Safari a Firefox, zatímco v Chrome je to víceméně stejné. To je velmi zajímavé!

Pokud máte připomínky k testu výkonu, dejte mi prosím vědět. Interní prvky prohlížeče jsou neuvěřitelně komplikované a někdy dojde k optimalizaci v testu, který pak celou věc zruší.

Také bych rád slyšel, jestli používáte Object.is ve vašem zdrojovém kódu! :)

Další zdroje

  • Jak jsou čísla kódována v JavaScriptu
  • Kapitola „Čísla“ v „Hovoření JavaScript
  • Proč má JavaScript dvě nuly:-0 a +0
  • Object.je na MDN