==:会进行隐式类型转换 (Coercion),尝试将两个值转换为相同类型后再比较。===:如果类型不同,直接返回 false。如果类型相同,再比较值。永远推荐使用 ===。如果有一个是数字,另一个也会被转换为数字。
如果有布尔值,布尔值先转为数字 (true -> 1, false -> 0)。
如果有一个是对象,会先将对象转换为原始值。
转换顺序:
obj[Symbol.toPrimitive](hint)obj.valueOf()obj.toString()[] == ![] 为什么是 true?步骤拆解:
![] 优先级更高,空数组转 Boolean 为 true,取反为 false。[] == false。false -> 0。[] == 0。[] 转换为原始值:[].valueOf() -> [] (非原始值),继续 [].toString() -> "" (空字符串)。"" == 0。Number("") -> 0。0 === 0 -> false (等等,这里逻辑错了?)❌ 修正逻辑:
![] -> false。[] == false。[] == 0。"" == 0。0 === 0 -> true。obj.valueOf 和toString 哪个先执行?如果是 == 比较,默认 hint 是 'default' (表现像 'number'),优先调用 valueOf。如果 valueOf 返回对象,再调用 toString。
Date 对象特殊,默认 hint 是 'string',优先 toString。
NaN:与任何值都不相等,包括自己。
+0 vs -0:
Object.is(val1, val2) 与 === 基本一致,只有两个区别:
+0 不等于 -0。NaN 等于 NaN。