You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: types-grammar/ch1.md
+80Lines changed: 80 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -618,6 +618,86 @@ Depending on how you interpret "smallest", you could either answer `0` or... `Nu
618
618
Number.MIN_SAFE_INTEGER; // -9007199254740991
619
619
```
620
620
621
+
#### Double Zeros
622
+
623
+
It may surprise you to learn that JS has two zeros: `0`, and `-0` (negative zero). But what on earth is a "negative zero"? A mathematician would surely balk at such a notion.
624
+
625
+
This isn't just a funny JS quirk; it's mandated by the IEEE-754[^IEEE754] specification. All floating point numbers are signed, including zero. And though JS does kind of hide the existence of `-0`, it's entirely possible to produce it and to detect it:
626
+
627
+
```js
628
+
function isNegZero(v) {
629
+
return v == 0 && (1 / v) == -Infinity;
630
+
}
631
+
632
+
regZero = 0 / 1;
633
+
negZero = 0 / -1;
634
+
635
+
regZero === negZero; // true -- oops!
636
+
Object.is(-0,regZero); // false -- phew!
637
+
Object.is(-0,negZero); // true
638
+
639
+
isNegZero(regZero); // false
640
+
isNegZero(negZero); // true
641
+
```
642
+
643
+
You may wonder why we'd ever need such a thing as `-0`. It can be useful when using numbers to represent both the magnitude of movement (speed) of some item (like a game character or an animation) and also its direction (e.g., negative = left, positive = right).
644
+
645
+
Without having a signed zero value, you couldn't tell which direction such an item was pointing at the moment it came to rest.
646
+
647
+
#### Invalid Number
648
+
649
+
Mathematical operations can sometimes produce an invalid result. For example, if you try to divide a number by a string (`42 / "Kyle"`), that's an invalid mathematical operation.
650
+
651
+
Another type of invalid numeric operation is trying to convert/coerce a non-numeric type of value to a `number`. We can do so with either the `Number(..)` function (no `new` keyword) or with the unary `+` operator in front of the value:
652
+
653
+
```js
654
+
myAge = Number("just a number");
655
+
656
+
myAge; // NaN
657
+
658
+
+undefined; // NaN
659
+
```
660
+
661
+
All such invalid operations (mathematical or numeric) produce the special `number` value called `NaN`.
662
+
663
+
The historical root of "NaN" (including from the IEEE-754[^IEEE754] specification) is as an acronym for "Not a Number". Unfortunately, that meaning produces confusion, since `NaN` is *absolutely* a `number`.
664
+
665
+
| TIP: |
666
+
| :--- |
667
+
| Why is `NaN` a `number`?!? Think of the opposite: what if a mathematical/numeric operation, like `+` or `/`, produced a non-`number` value (like `null`, `undefined`, etc)? Wouldn't that be really strange and unexpected? What if they threw exceptions, so that you had to `try..catch` all your math? The only sensible behavior is, numeric/mathematical operations should *always* produce a `number`, even if that value is invalid because it came from an invalid operation. |
668
+
669
+
To avoid such confusion, I strongly prefer to define "NaN" as any of the following instead:
670
+
671
+
* "iNvalid Number"
672
+
* "Not actual Number"
673
+
* "Not available Number"
674
+
* "Not applicable Number"
675
+
676
+
`NaN` is a special value in JS, in that it's the only value in the language that lacks the *identity property* -- it's never equal to itself.
677
+
678
+
```js
679
+
NaN === NaN; // false
680
+
```
681
+
682
+
So unfortunately, the `===` operator cannot check a value to see if it's `NaN`. But there are some ways to do so:
683
+
684
+
```js
685
+
politicianIQ = "nothing" / Infinity;
686
+
687
+
Number.isNaN(politicianIQ); // true
688
+
689
+
Object.is(NaN,politicianIQ); // true
690
+
[ NaN ].includes(politicianIQ); // true
691
+
```
692
+
693
+
Here's a fact of virtually all JS programs, whether you realize it or not: `NaN` happens. Seriously, almost all programs that do any math or numeric conversions are subject to `NaN` showing up.
694
+
695
+
If you're not properly checking for `NaN` in your programs where you do math or numeric conversions, I can say with some degree of certainty: you probably have a number bug in your program somewhere, and it just hasn't bitten you yet (that you know of!).
696
+
697
+
| WARNING: |
698
+
| :--- |
699
+
| JS originally provided a global function called `isNaN(..)` for `NaN` checking, but it unfortunately has a long-standing coercion bug. `isNaN("Kyle")` returns `true`, even though the string value `"Kyle"` is most definitely *not* the `NaN` value. This is because the global `isNaN(..)` function forces any non-`number` argument to coerce to a `number` first, before checking for `NaN`. Coercing `"Kyle"` to a `number` produces `NaN`, so now the function sees a `NaN` and returns `true`! This buggy global `isNaN(..)` still exists in JS, but should never be used. When `NaN` checking, always use `Number.isNaN(..)`, `Object.is(..)`, etc. |
700
+
621
701
### BigInteger Values
622
702
623
703
As the maximum safe integer in JS `number`s is `9007199254740991`, such a relatively low limit can present a problem if a JS program needs to do larger integer math, or even just hold values like 64-bit integer IDs (e.g., Twitter Tweet IDs).
0 commit comments