JavaScript 中的宽松相等(==)陷阱与最佳实践
在 JavaScript 中,==
被称为宽松相等运算符,它在比较时会进行类型转换(Type Coercion)。
这使得一些看似“不可思议”的表达式结果为 true
,经常让开发者感到困惑。
本文将带你梳理 ==
的常见陷阱,帮助你在开发中避免掉坑。
一、==
的基本规则
当两边类型不同的时候,==
会尝试进行隐式转换,大致规则如下:
- 布尔值会先转为数字(
true → 1
,false → 0
)。 - 字符串和数字比较时,字符串会尝试转为数字。
- **对象(包括数组)**会调用
toString()
或valueOf()
转换成原始值。 null
和undefined
只和彼此相等,不会等于其他值。
二、常见陷阱清单
1. null
和 undefined
null == undefined // true
null == 0 // false
undefined == 0 // false
👉 只有 null
和 undefined
相等。
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
这让 ==
的比较逻辑复杂且不直观。
四、最佳实践:如何避免掉坑?
-
统一使用严格相等
===
"3" === 3 // false (类型不同)
严格相等不会触发类型转换,更加安全。
-
显式转换类型
Number("3") === 3 Boolean([]) === false
-
避免直接比较数组和对象 在比较前先取值,而不是直接比较复杂结构。
-
使用 ESLint 等工具 可以开启
eqeqeq
规则,强制只能使用===
。
五、总结
==
的宽松相等在某些场景下看似方便,但它带来的隐式转换往往会埋下隐患。
在实际开发中,建议:
- 一律使用
===
- 需要比较时显式转换类型
这样既能保证代码的可读性,又能避免那些隐晦的 bug。