在 JavaScript 中,== 被称为宽松相等运算符,它在比较时会进行类型转换(Type Coercion)。 这使得一些看似“不可思议”的表达式结果为 true,经常让开发者感到困惑。

本文将带你梳理 == 的常见陷阱,帮助你在开发中避免掉坑。


一、== 的基本规则

当两边类型不同的时候,== 会尝试进行隐式转换,大致规则如下:

  1. 布尔值会先转为数字(true → 1, false → 0)。
  2. 字符串和数字比较时,字符串会尝试转为数字。
  3. **对象(包括数组)**会调用 toString()valueOf() 转换成原始值。
  4. nullundefined 只和彼此相等,不会等于其他值。

二、常见陷阱清单

1. nullundefined

null == undefined   // true
null == 0           // false
undefined == 0      // false

👉 只有 nullundefined 相等


2. 字符串与数字

"3" == 3        // true   ("3" → 3)
"0" == false    // true   ("0" → 0, false → 0)
"" == 0         // true   ("" → 0)
"  \t\n" == 0   // true   (空白字符串 → 0)

👉 字符串在比较时会转数字,容易出乎意料。


3. 布尔值

true == 1       // true
false == 0      // true
true == "1"     // true
false == []     // true   ([] → "" → 0)
false == "0"    // true   ("0" → 0)

👉 布尔值会被转为数字参与比较。


4. 数组

[3] == 3        // true   ([3].toString() → "3" → 3)
["3"] == 3      // true
[] == 0         // true   ([].toString() → "" → 0)
[] == false     // true   ([] → "" → 0, false → 0)

👉 数组会先变成字符串,再转成数字。


5. 对象

{} == {}                 // false  (不同引用)
{} == "[object Object]"  // false

👉 对象比较的是引用,只有同一个对象才相等。


6. 特殊情况

NaN == NaN   // false (NaN 不等于任何值)
[] == ![]    // true  (![] → false → 0, [] → "" → 0)

👉 NaN 是个特例,只能用 isNaN()Number.isNaN() 判断。 👉 [] == ![] 是典型面试题,结果居然是 true


三、为什么会这样?

这些现象都源于 JavaScript 的 类型转换规则

  • 对象 → 字符串:调用 toString()
  • 字符串 → 数字:用 Number() 转换
  • 布尔值 → 数字:true → 1, false → 0

这让 == 的比较逻辑复杂且不直观。


四、最佳实践:如何避免掉坑?

  1. 统一使用严格相等 ===

    "3" === 3  // false (类型不同)
    

    严格相等不会触发类型转换,更加安全。

  2. 显式转换类型

    Number("3") === 3
    Boolean([]) === false
    
  3. 避免直接比较数组和对象 在比较前先取值,而不是直接比较复杂结构。

  4. 使用 ESLint 等工具 可以开启 eqeqeq 规则,强制只能使用 ===


五、总结

== 的宽松相等在某些场景下看似方便,但它带来的隐式转换往往会埋下隐患。 在实际开发中,建议:

  • 一律使用 ===
  • 需要比较时显式转换类型

这样既能保证代码的可读性,又能避免那些隐晦的 bug。