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/ch4.md
+129Lines changed: 129 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1075,6 +1075,135 @@ But another minor fact you might consider: in performance benchmarks I've run ma
1075
1075
1076
1076
I'd observe that even many diehard `===` fans tend to concede that `== null` is at least one such case where `==` is preferable.
1077
1077
1078
+
#### `==`Boolean Gotcha
1079
+
1080
+
Aside from some coercive corner cases we'll address in the next section, probably the biggest gotcha to be aware of with `==` has to do with booleans.
1081
+
1082
+
Pay very close attention here, as it's one of the biggest reasons people get bitten by, and then come to despise, `==`. If you take my simple advice (at the end ofthis section), you'll never be a victim!
1083
+
1084
+
Consider the following snippet, and let's assume for a minute that `isLoggedIn` is *not* holding a `boolean`value (`true` or `false`):
1085
+
1086
+
```js
1087
+
if (isLoggedIn) {
1088
+
// ..
1089
+
}
1090
+
1091
+
// vs:
1092
+
1093
+
if (isLoggedIn == true) {
1094
+
// ..
1095
+
}
1096
+
```
1097
+
1098
+
We've already covered the first `if` statement form. We know `if` expects a `boolean`, so in this case `isLoggedIn` will be coerced to a `boolean` using the lookup table in the `ToBoolean()` abstract operation. Pretty straightforward to predict, right?
1099
+
1100
+
But take a look at the `isLoggedIn == true` expression. Do you think it's going to behave the same way?
1101
+
1102
+
If your instinct was *yes*, you've just fallen into a tricky little trap. Recall early in this chapter when I warned that the rules of `ToBoolean()` coercion only apply if the JS operation is actually activating that algorithm. Here, it seems like JS must be doing so, because `== true` seems so clearly a "boolean related" type of comparison.
1103
+
1104
+
But nope. Go re-read the `IsLooselyEqual()` algorithm (for `==`) earlier in the chapter. Go on, I'll wait. If you don't like my summary, go read the specification algorithm[^LooseEquality] itself.
1105
+
1106
+
OK, do you see anything in there that mentions invoking `ToBoolean()` under any circumstance?
1107
+
1108
+
Nope!
1109
+
1110
+
Remember: when the types of the two `==` operands are not the same, it prefers to coerce them both to numbers.
1111
+
1112
+
What might be in `isLoggedIn`, if it's not a `boolean`? Well, it could be a string value like `"yes"`, forexample. In that form, `if ("yes") { .. }` would clearly pass the conditional check and execute the block.
1113
+
1114
+
But what's going to happen with the `==` form of the `if` conditional? It's going to act like this:
1115
+
1116
+
```js
1117
+
// (1)
1118
+
"yes" == true
1119
+
1120
+
// (2)
1121
+
"yes" == 1
1122
+
1123
+
// (3)
1124
+
NaN == 1
1125
+
1126
+
// (4)
1127
+
NaN === 1 // false
1128
+
```
1129
+
1130
+
So in other words, if`isLoggedIn` holds a value like `"yes"`, the `if (isLoggedIn) { .. }` block will pass the conditional check, but the `if (isLoggedIn == true)` check will not. Ugh!
1131
+
1132
+
What if`isLoggedIn` held the string `"true"`?
1133
+
1134
+
```js
1135
+
// (1)
1136
+
"true" == true
1137
+
1138
+
// (2)
1139
+
"true" == 1
1140
+
1141
+
// (3)
1142
+
NaN == 1
1143
+
1144
+
// (4)
1145
+
NaN === 1 // false
1146
+
```
1147
+
1148
+
Facepalm.
1149
+
1150
+
Here's a pop quiz: what value would `isLoggedIn` need to hold for both forms of the `if` statement conditional to pass?
1151
+
1152
+
...
1153
+
1154
+
...
1155
+
1156
+
...
1157
+
1158
+
...
1159
+
1160
+
What if `isLoggedIn` was holding the number `1`? `1` is truthy, so the `if (isLoggedIn)` form passes. And the other `==` form that involves coercion:
1161
+
1162
+
```js
1163
+
// (1)
1164
+
1 == true
1165
+
1166
+
// (2)
1167
+
1 == 1
1168
+
1169
+
// (3)
1170
+
1 === 1 // true
1171
+
```
1172
+
1173
+
But if `isLoggedIn` was instead holding the string `"1"`? Again, `"1"` is truthy, but what about the `==` coercion?
1174
+
1175
+
```js
1176
+
// (1)
1177
+
"1" == true
1178
+
1179
+
// (2)
1180
+
"1" == 1
1181
+
1182
+
// (3)
1183
+
1 == 1
1184
+
1185
+
// (4)
1186
+
1 === 1 // true
1187
+
```
1188
+
1189
+
OK, so `1` and `"1"` are two values that `isLoggedIn` can hold that are safe to coerce along with `true` in a `==` equality check. But basically almost no other values are safe for `isLoggedIn` to hold.
1190
+
1191
+
We have a similar gotcha if the check is `== false`. What values are safe in such a comparison? `""` and `0` work. But:
1192
+
1193
+
```js
1194
+
if ([] == false) {
1195
+
// this will run!
1196
+
}
1197
+
```
1198
+
1199
+
`[]` is a truthy value, but it's also coercively equal to `false`?! Ouch.
1200
+
1201
+
What are we to make of these gotchas with`== true` and `== false` checks?I have a plain and simple answer.
1202
+
1203
+
Never, ever, under any circumstances, perform a `==` check if either side of the comparison is a `true` or `false`value. It looks like it's going to behave as a nice `ToBoolean()` coercion, but it slyly won't, and will instead be ensnared in a variety of coercion corner cases (addressed in the next section). And avoid the `===` forms, too.
1204
+
1205
+
When you're dealing with booleans, stick to the implicitly coercive forms that are genuinely activating `ToBoolean()`, such as `if (isLoggedIn)`, and stay away from the `==` / `===` forms.
1206
+
1078
1207
## Coercion Corner Cases
1079
1208
1080
1209
I've been clear in expressing my pro-coercion opinion thus far. And it *is* just an opinion, though it's based on interpreting facts gleaned from studying the language specification and observable JS behaviors.
0 commit comments