人人都会AI编程

相等运算符 == 转换规则

更新时间:2026-07-11

== 是 JavaScript 中的抽象相等比较运算符,它和 ===(严格相等)的区别在于:== 在比较两个值是否相等之前,会尝试将它们转换为相同的类型。而 === 则不会做任何类型转换,类型不同直接返回 false

正因为有这种隐式类型转换,== 的行为时常会违反直觉,成为让开发者“踩坑”的重灾区。彻底搞清楚这套转换规则,不是为了让代码变得花哨,而是为了看懂别人的代码以及深谙其陷阱后坚定地选择避让

转换规则速查表

ECMAScript 规范定义了完整的“抽象相等比较算法”(Abstract Equality Comparison),梳理成日常可用的形式如下:

| 比较双方的类型 | 转换规则 |
| --- | --- |
| 类型相同 | 直接使用 === 比较,不转换(注意:NaN !== NaN+0 === -0)。 |
| nullundefined | null == undefinedtrue;与其他任何值比较均为 false。 |
| 一方为数字,一方为字符串 | 将字符串转换为数字后比较。 |
| 一方为布尔值 | 先将布尔值转换为数字(true → 1false → 0),然后再按上述规则比较。 |
| 一方为对象,一方为数字/字符串 | 调用对象的 valueOf() / toString() 取得原始值后再按上述规则比较。 |
| 其他组合 | 均返回 false。 |

注意:BigInt== 的交互有额外规则,本书基于 ES6+ 核心语法,暂不展开。

一步一步推演几个典型案例

光看表格不够直观,我们拿几个常被问到甚至让面试官“自相残杀”的案例走一遍过程。

案例 1:0 == false 为什么是 true

  1. 双方类型不同:false 是布尔值,0 是数字。
  2. 规则:“一方为布尔值” → 将布尔值转换为数字,false 变成 0
  3. 现在变成 0 == 0,类型相同,严格相等,结果为 true

同理:1 == true 也是 truetrue → 1),但 2 == truefalse2 == 1 不成立)。

案例 2:'' == 0 为什么是 true

  1. 类型:空字符串是字符串,0 是数字。
  2. 规则:“一方为数字,一方为字符串” → 将字符串转换为数字,'' 转换为 0
  3. 变成 0 == 0,结果为 true

同理:'123' == 123 成立,'abc' == NaN 不成立(NaN == 任何值 都是 false)。

案例 3:[] == 0 为什么是 true?(经典烧脑题)

  1. 类型:[] 是对象,0 是数字。
  2. 规则:“一方为对象,一方为数字” → 需要先将对象转为原始值。
  3. 数组 [] 的转换:先调用 valueOf(),得到 [] 本身(不是原始值),于是再调用 toString(),得到 ''(空字符串)。
  4. 现在变成了 '' == 0,正巧是我们刚分析过的案例 2 —— 结果为 true

由此可以推演出另一个著名等式:[] == falsetruefalse → 0[] → '' → 00 == 0)。

案例 4:[] == ![] 为什么是 true?(绝对反直觉)

  1. ![] 先被计算:[] 是真值(truthy),![] 就是 false
  2. 现在变成 [] == false,与上一例相同,结果为 true

这完全是两套规则组合出的“彗星撞地球”式巧合,也充分展示了串联转换有多么不可预测。

案例 5:null == undefinednull == 0

  • null == undefined:符合特殊规则,直接返回 true
  • null == 0null 仅与 undefined 相等,与其他任何值比较都返回 false

很多开发者在后端语言中习惯了 null == 0true,在 JavaScript 中要特别留神。

常见易错点汇总

  • 布尔值的转换优先级很高:一旦有布尔值参与,会先将其转为数字,而不是期望的“把另一方转为布尔”。因此 'false' == falsefalse'false' 是非空字符串转为 NaN,false 转为 0,NaN ≠ 0)。
  • 对象转原始值可能产生意外空白:对象 → 空字符串 → 0 这条转换链是很多诡异结果的根源。
  • NaN 是唯一的“自己不等于自己”的值NaN == NaNfalse
  • 不要期望 == 用于与 nullundefined 的宽松比较能解决所有空值问题x == null 看似能同时检测 nullundefined,一旦项目中混入其他假值(0''false),逻辑就可能悄悄崩坏。

最佳实践

在日常开发中,强烈推荐统一使用 === 进行相等判断。它简单、明确、没有暗箱操作,能把潜在的隐式转换问题挡在门外。唯一的例外是明确知道自己在做什么,并且代码上下文极度清晰(例如有意使用 x == null 来一次性排除 nullundefined),即便如此也应在代码中加上清晰的注释。

记住一句话:能不用 == 就不用 ==,代码的可读性和可维护性远胜于节省几次键盘敲击。如果你以后看到其他人写的 ==,就用这节的规则去分析,你会逐渐发现,多数“巧妙”的用法最终都演变成了技术债务。