主题
JavaScript 抽象类型比较(==)详解
在 JavaScript 中,抽象相等比较(==)和严格相等比较(===)在使用时可能返回值不一致。== 在比较时会执行内部的类型转换规则,被称为 抽象类型比较算法。
本文将从“相同类型”与“不同类型”开始介绍,整理了 == 的转换行为。
一、相同类型的比较
当两边的值类型相同时,抽象比较不会进行类型转换,直接比较它们的值(或引用)。
1. 普通值类型(number, string, boolean, bigint, symbol)
直接比较值是否相等:
js
1 == 1 // true
'abc' == 'abc' // true
true == true // true2. 引用类型(如对象、数组、函数)
比较的是内存引用地址是否一致:
js
const a = { x: 1 }
const b = a
const c = { x: 1 }
a == b // true,同一个引用
a == c // false,不同引用3. NaN 特例
不管 NaN == NaN 还是 NaN === NaN,结果都为 false:
js
NaN == NaN // false二、不同类型的比较(抽象转换规则)
当比较的两边类型不同时,JavaScript 会进行内部的类型转换步骤,再去进行比较。
转换原则:
- 如果其中一边是对象,则尝试将其转换为原始类型。
- 普通类型之间,尝试转换为 number 再比较。
1. null 和 undefined
这是一个特例:
js
null == undefined // true
null == false // false
undefined == 0 // false
null == '' // false- 这两个是唯一一对类型不同但被认为相等的值
- 这两个值属于原始类型,但是不遵守原始类型的转换规则
不会转number
小细节
jsNumber(null) // 0 Number(undefined) // NaN
- 虽然Number函数可以将null转为0
- 但是这个转换结果不会应用在抽象类型比较中,是属于Number函数内部的行为
2. 原始类型之间(string, number, boolean)
当两边是不同的原始类型,通常都会先转换为 number 再比较:
js
'1' == 1 // true -> '1' 转成 1
true == 1 // true -> true 转成 1
false == 0 // true -> false 转成 0
'0' == false // true -> '0' -> 0, false -> 03. 对象与原始值之间的比较
对象参与比较时,JavaScript 会尝试将对象转换为原始值。这依赖于对象的 valueOf() 和 toString() 方法。
转换步骤:
- 优先调用
obj.valueOf(),如果返回原始类型,就用此值比较 - 否则再调用
obj.toString(),如果返回原始类型,就用此值比较 - 如果两者都未返回原始值,则抛出错误。
js
const obj = {
valueOf() {
return 42
}
}
obj == 42 // true -> valueOf() 返回原始值 42,类型一致,直接比较如果 valueOf() 返回的是对象,则继续尝试调用 toString():
js
const obj = {
valueOf() {
return {}
},
toString() {
return '123'
}
}
obj == 123 // true -> toString() 返回 '123',转成数字 123,再比较比较的两个值如果类型仍不一致,会再转为 number 比较:
js
{} == '[object Object]' // true
{} == 0 // false(对象转为 NaN,由于NaN不等于任何值,所以返回false)4. Date 对象的例外
在大多数对象中,valueOf() 优先于 toString(),但 Date 是例外:
Date 优先调用
toString()而不是valueOf()。
js
const d = new Date('2025-05-25T14:42:31')
console.log(d.valueOf()) // 返回时间戳
console.log(d.toString()) // 返回格式化时间字符串
d == d.toString() // true三、总结
| 情况 | 行为说明 |
|---|---|
| 相同类型原始值 | 直接比较值是否相等 |
| 相同类型对象 | 比较引用是否相等 |
| 任一值为 NaN | 返回 false,NaN和任何值都不相等 |
| null == undefined | true(特例) |
| 不同类型原始值 | 转换为 number 后比较 |
| 对象与原始值 | 对象 → valueOf() → toString() → 转 number 后比较 |
| Date 对象 | 优先调用 toString() 再比较 |
四、建议
- 应该避免使用
==,优先使用===,可以减少类型转换带来的意外。 - 如果确实需要
==,一定要先清楚转换规则,避免代码出现意外。
五、对象转布尔与相等比较的区别(易混淆点)
JavaScript 中,任何非 null、undefined、0、NaN、''、false 的值在布尔上下文中都被认为是 真值(truthy)。但对象即使“包装了 false”,也被认为是 truthy。
js
Boolean(new Boolean(false)) // true
new Boolean(false) == false // true解释:
Boolean(new Boolean(false))的逻辑是:传入一个对象 → 对象是 truthy → 返回truenew Boolean(false) == false的逻辑是:- 左边是对象,触发抽象相等比较
- 调用
valueOf()得到原始值:false false == false,返回true
说明了:
Boolean()是显式转换为布尔值,不涉及抽象相等比较==则是试图把对象“解包”成原始值,再进行比较
