forked from ascoders/weekly
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
130 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
本期精读的文章是:[null >= 0?](https://blog.campvanilla.com/javascript-the-curious-case-of-null-0-7b131644e274) | ||
|
||
# 1 引言 | ||
|
||
<img src="assets/24/gt.jpeg" width="500" alt="logo" /> | ||
|
||
你是如何看待 null >= 0 为 `true` 这个结果的呢?要么选择勉强接受,要么跟着我一探究竟吧。 | ||
|
||
# 2 内容概要 | ||
|
||
## 大于判断 | ||
|
||
javascript 在判断 `a > b` 时,记住下面 21 步判断法: | ||
|
||
1. 调用 b 的 ToPrimitive(hit Number) 方法. | ||
2. 调用 a 的 ToPrimitive(hit Number) 方法. | ||
3. 如果此时 Result(1) 与 Result(2) 都是字符串,跳到步骤 16. | ||
4. 调用 ToNumber(Result(1)). | ||
5. 调用 ToNumber(Result(2)). | ||
6. 如果 Result(4) 为 NaN, return undefined. | ||
7. 如果 Result(5) 为 NaN, return undefined. | ||
8. 如果 Result(4) 和 Result(5) 是相同的数字,return false. | ||
9. 如果 Result(4) 为 +0, Result(5) 为 -0, return false. | ||
10. 如果 Result(4) 为 -0, Result(5) 为 +0, return false. | ||
11. 如果 Result(4) 为 +∞, return false. | ||
12. 如果 Result(5) 为 +∞, return true. | ||
13. 如果 Result(5) 为 -∞, return false. | ||
14. 如果 Result(4) 为 -∞, return true. | ||
15. 如果 Result(4) 的数值大小小于 Result(5),return true,否则 return false. | ||
16. 如果 Result(2) 是 Result(1) 的前缀 return false. (比如 "ab" 是 "abc" 的前缀) | ||
17. 如果 Result(1) 是 Result(2) 的前缀, return true. | ||
18. 找到一个位置 k,使得 a[k] 与 b[k] 不相等. | ||
19. 取 m 为 a[k] 字符的数值. | ||
20. 取 n 为 b[k] 字符的数值. | ||
21. 如果 m < n, return true,否则 return false. | ||
|
||
> ToPrimitive 会按照顺序优先使用存在的值:valueOf()、toString(),如果都没有,会抛出异常。 | ||
> ToPrimitive(hit Number) 表示隐转数值类型 | ||
所以 null > 0 结果为 `false`。 | ||
|
||
## 等于判断 | ||
|
||
现在看看 `a == b` 时的表现(三等号会严格判断类型,两等号反而是最复杂的情况)。 | ||
|
||
1. 如果 a 与 b 的类型相同,则: | ||
- 如果 Type(b) 为 undefined,return true. | ||
- 如果 Type(b) 为 null,return true. | ||
- 如果 Type(b) 为 number,则: | ||
- 如果 b 为 NaN,return false. | ||
- 如果 a 为 NaN,return false. | ||
- 如果 a 与 b 数值相同,return true. | ||
- 如果 a 为 +0,b 为 -0,return true. | ||
- 如果 a 为 -0,b 为 +0,return true. | ||
- 否则 return false. | ||
- 如果 Type(b) 为 string,且 a 与 b 是完全相同的字符串,return true,否则 return false. | ||
- 如果 Type(b) 是 boolean,如果都是 true 或 false,return true,否则 return false. | ||
- 如果 a 与 b 是同一个对象引用,return true,否则 return false. | ||
2. 如果 a 为 null,b 为 undefined,return true. | ||
3. 如果 a 为 undefined,b 为 null,return true. | ||
4. 如果 Type(a) 为 number,Type(b) 为 string,返回 a == ToNumber(b) 的结果. | ||
5. 如果 Type(a) 为 string,Type(b) 为 number,返回 ToNumber(a) == b 的结果. | ||
6. 如果 Type(a) 为 boolean,返回 ToNumber(a) == b 的结果. | ||
7. 如果 Type(b) 为 boolean,返回 a == ToNumber(b) 的结果. | ||
8. 如果 Type(a) 是 string 或 number,且 Type(b) 是对象类型,返回 a == ToPrimitive(b) 的结果. | ||
9. 如果 Type(a) 是对象类型,且 Type(b) 是 string 或 number,返回 ToPrimitive(a) == b 的结果. | ||
10. 否则 return false. | ||
|
||
所以 null == 0 走到了第 10 步,返回了默认的 `false`。 | ||
|
||
## 大于等于判断 | ||
|
||
javascript 是这么定义大于等于判断的: | ||
|
||
> 如果 a < b 为 `false`,则 a >= b 为 `true` | ||
所以 null >= 0 为 `true`,因为 null < 0 是 `false`. | ||
|
||
# 3 精读 | ||
|
||
### 关于 toPrimitive | ||
|
||
拓展一下,我们可以通过 `Symbol.toPrimitive` 定义某个 class 的 ToPrimitive 行为,比如: | ||
|
||
```javascript | ||
|
||
class AnswerToLifeAndUniverseAndEverything { | ||
[Symbol.toPrimitive](hint) { | ||
if (hint === 'string') { | ||
return 'Like, 42, man'; | ||
} else if (hint === 'number') { | ||
return 42; | ||
} else { | ||
// when pushed, most classes (except Date) | ||
// default to returning a number primitive | ||
return 42; | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### 还有不按套路出牌的情况? | ||
|
||
按上面的道理,我们可以举一反三: | ||
|
||
```javascript | ||
{} >= {} // true | ||
``` | ||
|
||
可是这是为何呢? | ||
|
||
```javascript | ||
null >= {} // false | ||
``` | ||
|
||
仔细读过上文应该不难发现,如果 ToPrimitive(hit Number) 出现了 NaN,将直接 return undefined,也就是打印出 false,而下面是隐式转换表,{} 的结果是 NaN,因此结果是 false。 | ||
|
||
![primitive](https://camo.githubusercontent.com/c8ccc486bd441453d9c3529ed6d3b26661541787/68747470733a2f2f692e6c6f6c692e6e65742f323031372f30392f32322f353963346362316238336434632e706e67) | ||
|
||
# 4 总结 | ||
|
||
NaN 在 javascript 是个特殊存在,只有 `isNaN` 可以准确判断到它,而且使用它进行比较判断时,会直接 return false. | ||
|
||
javascript 隐式转换有一套优先级规则,而且不同值的隐式转换还需要对照表记忆,还存在 `ToPrimitive(hint Number)` `ToPrimitive(hint String)` `ToPrimitive(hint Boolean)` 三份表,记忆起来确实有点复杂。 | ||
|
||
因此推荐比较判断时,尽量使用 `===`,通过 `Typescript` `Flow` 等强类型语言约束变量类型,尽量不要做不同类型变量间的比较。 | ||
|
||
> 讨论地址是:[精读《null >= 0?》 · Issue #36 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/36) | ||
> 如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.