最好不要在 JS 中使用 ==

260 阅读4分钟

最好不要在 JS 中使用 ==
最好不要在 JS 中使用 ==
最好不要在 JS 中使用 ==

不信?请看下面题目:

[[] == false, ['0'] == false, [1] == true, ['2'] == true, [[['3']]] == 3 ]

运行结果如下:

[true, true, true, false, true]

如果你一眼就能准确的看出上述代码的返回结果,那就当我没说。

如果不能,那我们还是最好不要使用 == 了吧。

看似很诡异,其实 == 是有自己的比较规则的,其规则如下:

抽象相等比较算法

以 x 和 y 为值进行 x == y 比较会产生的结果可为 true 或 false。比较的执行步骤如下:

  1. 若 Type(x) 与 Type(y) 相同, 则:
    1. 若 Type(x) 为 Undefined, 返回 true
    2. 若 Type(x) 为 Null, 返回 true
    3. 若 Type(x) 为 Number,则:
      1. 若 x 为 NaN,返回 false
      2. 若 y 为 NaN,返回 false
      3. 若 x 与 y 为相等数值,返回 true
      4. 若 x 为 +0 且 y 为 −0,返回 true
      5. 若 x 为 −0 且 y 为 +0,返回 true
      6. 返回 false
    4. 若 Type(x) 为 String,则当 x 和 y 为完全相同的字符序列(长度相等且相同字符在相同位置)时返回 true,否则,返回 false
    5. 若 Type(x) 为 Boolean,当 x 和 y 同为 true 或者同为 false 时返回 true,否则,返回 false
    6. 当 x 和 y 为引用同一对象时返回 true,否则,返回 false
  2. 若 x 为 null 且 y 为 undefined,返回 true
  3. 若 x 为 undefined 且 y 为 null,返回 true
  4. 若 Type(x) 为 Number 且 Type(y) 为 String,返回 x == ToNumber(y) 的结果;
  5. 若 Type(x) 为 String 且 Type(y) 为 Number,返回比较 ToNumber(x) == y 的结果;
  6. 若 Type(x) 为 Boolean,返回比较 ToNumber(x) == y 的结果;
  7. 若 Type(y) 为 Boolean,返回比较 x == ToNumber(y) 的结果;
  8. 若 Type(x) 为 String 或 Number,且 Type(y) 为 Object,返回比较 x == ToPrimitive(y) 的结果;
  9. 若 Type(x) 为 Object 且 Type(y) 为 String 或 Number,返回比较 ToPrimitive(x) == y 的结果;
  10. 返回 false

问题解析

根据规则,我们来分析一下问题。以 [] == false 为例,他的比较过程应该是这样的:

  1. [] == false =[根据第 7 条]=>
  2. [] == Number(false) = [] == 0 =[根据第 9 条]=>
  3. Number([].toString()) == 0 = Number('') == 0 = 0 == 0 =[根据第 1.3.3 条]=>
  4. 返回 true

他们都转成了数字,想不到吧。

规则总结

总体来说,== 比较分为 2 种情况:需要类型转换的和不需要类型转换的。

不需要类型转换的比较

这类主要靠记忆,总结如下:

  1. null == undefined 返回 true;
  2. NaN 和任何东西都不相等,包括他自己;
  3. 0 在比较的时候不分正负,即:+0 等于 -0
  4. 类型相同的比较,就不说了;

注意nullundefined=== 下不成立。

需要类型转换的比较

需要类型转换的前提是比较的双方类型不相同。

  1. boolean 类型转成 number 类型;
  2. number 类型比较都转 number,对象先调一下 toString 再转 number
  3. 如果和 string 类型比较(比较对象不是 number),转一下字符串;

=== 对比

是不是比较麻烦,我有一个好办法,那就是不要用 ==,使用 ===

严格等于(===)比较算法如下:

比较 x === yx 和 y 为值,需要产出 true 或 false。比较过程如下:

  1. 如果 Type(x) 与 Type(y) 的结果不一致,返回 false
  2. 如果 Type(x) 结果为 Undefined,返回 true
  3. 如果 Type(x) 结果为 Null,返回 true
  4. 如果 Type(x) 结果为 Number,则:
    1. 如果 x 为 NaN,返回 false
    2. 如果 y 为 NaN,返回 false
    3. 如果 x 与 y 为同一个数字,返回 true
    4. 如果 x 为 +0y 为 -0,返回 true
    5. 如果 x 为 -0y 为 +0,返回 true
    6. 返回 false
  5. 如果 Type(x) 结果为 String,如果 x 与 y 为完全相同的字符序列(相同的长度和相同的字符对应相同的位置),返回 true,否则,返回 false
  6. 如果 Type(x) 结果为 Boolean,如果 x 与 y 都为 true 或 false,则返回 true,否则,返回 false
  7. 如果 x 和 y 引用到同一个 Object 对象,返回 true,否则,返回 false

=== 简单直接,对于不同类型直接返回 false,节省了类型转换的时间。

参考资料