Skip to content

Commit 33f6bf4

Browse files
committed
types-grammar, ch4: adding 'nullish' equality discussion
1 parent f4ae6d8 commit 33f6bf4

File tree

1 file changed

+68
-2
lines changed

1 file changed

+68
-2
lines changed

types-grammar/ch4.md

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,25 @@ We can see the `0` / `-0` misdirection of `SameValueZero()` here:
964964
(new Map([[ 0, "ok" ]])).has(-0); // true <--- :(
965965
```
966966

967-
In these cases, there's a *coercion* (of sorts!) that treats `-0` and `0` as indistinguishable. No, that's not technically a *coercion* in that the type is not being changed, but I'm sort of fudging the definition to *include* this case in our broader discussion of coercion here.
967+
In these cases, there's a *coercion* (of sorts!) that treats `-0` and `0` as indistinguishable. No, that's not technically a "coercion" in that the type is not being changed, but I'm sort of fudging the definition to *include* this case in our broader discussion of coercion here.
968+
969+
Contrast the `includes()` / `has()` methods here, which activate `SameValueZero()`, with the good ol' `indexOf(..)` array utility, which instead activates `IsStrictlyEqual()` instead. This algorithm is slightly more "coercive" than `SameValueZero()`, in that it prevents `NaN` values from ever being treated as equal to each other:
970+
971+
```js
972+
[ 1, 2, NaN ].indexOf(NaN); // -1 <--- not found
973+
```
974+
975+
If these nuanced quirks of `includes(..)` and `indexOf(..)` bother you, when searching -- looking for an equality match within -- for a value in an array, you can avoid any "coercive" quicks and *force* the strictest `SameValue()` equality matching, via `Object.is(..)`:
976+
977+
```js
978+
vals = [ 0, 1, 2, -0, NaN ];
979+
980+
vals.find(v => Object.is(v,-0)); // -0
981+
vals.find(v => Object.is(v,NaN)); // NaN
982+
983+
vals.findIndex(v => Object.is(v,-0)); // 3
984+
vals.findIndex(v => Object.is(v,NaN)); // 4
985+
```
968986

969987
#### Equality Operators: `==` vs `===`
970988

@@ -1005,7 +1023,55 @@ I'll be revisiting this topic to make the case for preferring `==` over `===`, l
10051023
10061024
#### Nullish Coercion
10071025
1008-
// TODO
1026+
We've already seen a number of JS operations that are nullish -- treating `null` and `undefined` as coercively equal to each other, including the `?.` optional-chaining operator and the `??` nullish-coalescing operator (see "Null'ish" in Chapter 1).
1027+
1028+
But `==` is the most obvious place that JS exposes nullish coercive equality:
1029+
1030+
```js
1031+
null == undefined; // true
1032+
```
1033+
1034+
Neither `null` nor `undefined` will ever be coercively equal to any other value in the language, other than to each other. That means `==` makes it ergonomic to treat these two values as indistinguishable.
1035+
1036+
You might take advantage of this capability as such:
1037+
1038+
```js
1039+
if (someData == null) {
1040+
// `someData` is "unset" (either null or undefined),
1041+
// so set it to some default value
1042+
}
1043+
1044+
// OR:
1045+
1046+
if (someData != null) {
1047+
// `someData` is set (neither null nor undefined),
1048+
// so use it somehow
1049+
}
1050+
```
1051+
1052+
Remember that `!=` is the negation of `==`, whereas `!==` is the negation of `===`. Don't match the count of `=`s unless you want to confuse yourself!
1053+
1054+
Compare these two approaches:
1055+
1056+
```js
1057+
if (someData == null) {
1058+
// ..
1059+
}
1060+
1061+
// vs:
1062+
1063+
if (someData === null || someData === undefined) {
1064+
// ..
1065+
}
1066+
```
1067+
1068+
Both `if` statements will behave exactly identically. Which one would you rather write, and which one would you rather read later?
1069+
1070+
To be fair, some of you prefer the more verbose `===` equivalent. And that's OK. I disagree, I think the `==` version of this check is *much* better. And I also maintain that the `==` version is more consistent in stylistic spirit with how the other nullish operators like `?.` and `??` act.
1071+
1072+
But another minor fact you might consider: in performance benchmarks I've run many times, JS engines can perform the single `== null` check as shown *slightly faster* than the combination of two `===` checks. In other words, there's a tiny but measurable benefit to letting JS's `==` perform the *implicit* nullish coercion than in trying to *explicitly* list out both checks yourself.
1073+
1074+
I'd observe that even many diehard `===` fans tend to concede that `== null` is at least one such case where `==` is preferable.
10091075

10101076
## Coercion Corner Cases
10111077

0 commit comments

Comments
 (0)