在 JavaScript 中,== 、===和 Object.is() 是三种常见的相等性判断方式。它们的主要区别在于类型转换行为以及对 NaN、+0/-0 的特殊处理。
核心区别速览
| 特性 | ==(宽松相等) | ===(严格相等) | Object.is()(精确相等) |
|---|---|---|---|
| 类型转换 | 会隐式转换 | 不转换,类型不同直接false | 不转换,类型不同直接false |
1 == '1' | true | false | false |
null == undefined | true | false | false |
NaN == NaN | false | false | true |
+0 == -0 | true | true | false |
| 推荐场景 | 现代开发不推荐或需要自动转换时(慎用) | 日常开发首选,绝大多数比较场景 | 需要精确处理NaN或+0/-0时 |
==(宽松相等
- 会进行类型转换(强制类型转换),再比较值是否相等。
- 规则较复杂,常见场景:
null == undefined → rue- 字符串和数字比较时,字符串会转为数字:
'5' == 5 → true - 布尔值与其他类型比较时,布尔值先转为数字:
true == 1 → true - 对象与原始值比较时,对象会尝试转成原始值
(valueOf/toString)
- 缺点:规则复杂、容易引发难以排查的 Bug,现代 JS 规范(如 Airbnb 规范)明确建议禁用
==。
0==false// true (false 转为 0)''==false// truenull==undefined// true1=='1'// true ('1' 转为 1)NaN==NaN// false===(严格相等)
- 不进行类型转换,类型不同直接返回
false。 - 类型相同时,按值比较:
- 基本类型:值相同即
true - 对象/数组/函数:比较的是引用地址,而非内容
- 基本类型:值相同即
- 但是有两个“反直觉”的特性:
NaN === NaN返回false(按照 IEEE 754 标准,NaN 不等于自身)+0 === -0返回true(+0 和 -0 被视为相等)
1==='1'// falsenull===undefined// falseNaN===NaN// false+0===-0// true{}==={}// falseObject.is()(同值相等)
- 行为基本与
===相同,但对两个特殊情况做了修正:Object.is(NaN, NaN)返回trueObject.is(+0, -0)返回false
- 除此之外,和
===判断结果完全一致(不进行类型转换)。
Object.is(1,'1')// falseObject.is(null,undefined)// falseObject.is(NaN,NaN)// trueObject.is(+0,-0)// falseObject.is(0,-0)// falseObject.is(0,+0)// true- 适用场景:
- 需要准确判断
NaN(如实现缓存键比对、状态管理) - 需要区分
+0和-0(如数学计算、Canvas/WebGL 底层逻辑) - 库/框架内部实现(如 React 的
Object.is用于判断 props 是否变化)
- 需要准确判断
最佳实践建议
| 需求 | 推荐写法 |
|---|---|
| 常规相等判断 | a === b |
判断是否为NaN | Number.isNaN(a)或Object.is(a, NaN) |
| 区分正负零 | Object.is(a, -0) |
| 比较对象/数组内容是否相同 | 使用深比较库(如 lodash.isEqual) |
遗留代码中见到== | 逐步替换为===,并补充类型校验 |
代码示例对比
// 类型转换差异console.log(1=='1');// trueconsole.log(1==='1');// falseconsole.log(Object.is(1,'1'));// false// NaN 处理console.log(NaN==NaN);// falseconsole.log(NaN===NaN);// falseconsole.log(Object.is(NaN,NaN));// true// 正负零处理console.log(+0==-0);// trueconsole.log(+0===-0);// trueconsole.log(Object.is(+0,-0));// false// 对象引用consta={x:1};constb={x:1};console.log(a==b);// falseconsole.log(a===b);// falseconsole.log(Object.is(a,b));// false使用建议
- 大多数情况优先用
===,避免隐式转换带来的意外。 - 当需要判断某个值严格是
NaN或者需要区分+0和-0时,再考虑Object.is()(或直接用Number.isNaN()) ==很少使用,除非明确需要null == undefined这类特性,或处理一些老代码。
简单总结:
==有类型转换,最宽松;===无类型转换,但不分辨 NaN 和 +0/-0;Object.is()是更精确的严格相等,修正了 NaN 和带符号零的比较。