Important
等值检测的目的是判断两个变量是否相等。这其中,运算符“==”和“!=”的运算效果称为“相等”和“不等”,而“===”和“!==”的运算效果称为“严格相等”和“严格不相等”。
| 运算符 | 名称 | 说明 |
|---|---|---|
| == | 相等 | 比较两个表达式,看是否相等 |
| != | 不等 | 比较两个表达式,看是否不相等 |
| === | 严格相等 | 是否相等并具有相同的数据类型 |
| !== | 不严格相等 | 是否具有不相等的值或不同的数据类型 |
等值检测中“相等“的运算规则
| 类型 | 运算规则 |
|---|---|
| 值类型与引用类型 | 将引用类型的数据转换为与值类型数据相同的数据,再进行”数据等值“比较 |
| 两个值类型 | 转换成相同数据类型的值进行”数据等值“比较 |
| 两个引用类型 | 比较引用地址 |
在三种值类型(数值、布尔值和字符串)中,如果两个被比较的值类型不同,那么:
- 有任何一个是数字时,会将另一个转换为数字进行比较
- 有任何一个是布尔值时,它将被转换为数字进行比较(并且由于上一规则的存在,所以另一个数据也将被转换为数字)
- 有任何一个是对象(或函数)时,将调用该对象的valueOf()方法来将其转换为值数据进行比较,且在多数情况下该值数据作为数字值处理
- 按照特定规则返回比较结果,例如,undefined 与 null 值总是相等的
- 如果有任一操作数是NaN,则相等操作符返回false,不相等操作符返回true。记住:即使两
个操作数都是NaN,相等操作符也返回false,因为按照规则,NaN不等于NaN - null 和 undefined 不能转换为其他类型的值再进行比较
| 表达式 | 结果 |
|---|---|
| null == undefined | true |
| "NaN" == NaN | false |
| NaN == NaN | false |
| false == 0 | true |
| true == 1 | true |
| true == 2 | false |
| undefined == 0 | false |
| null == 0 | false |
| "5" == 5 | true |
| {} == {} | false |
可见,JavaScript总是尽量用数字值比较来实现等值检测
等值检测中“严格相等“的运算规则
| 类型 | 运算规则 |
|---|---|
| 值类型与引用类型 | 必然不严格相等 |
| 两个值类型 | 如果数据类型不同,必然不严格相等;否则”数据等值“比较 |
| 两个引用类型 | 比较引用地址 |
虽然null == undefined 是 true,但 null === undefined 是false,因为它们不是相同的数据类型
Object.is()
在ECMAScript 6之前,有些特殊情况即使是===操作符也无能为力:
// 这些是===符合预期的情况
console.log(true === 1); // false
console.log({} === {}); // false
console.log("2" === 2); // false
// 这些情况在不同JavaScript引擎中表现不同,但仍被认为相等
console.log(+0 === -0); // true
console.log(+0 === 0); // true
console.log(-0 === 0); // true
// 要确定NaN的相等性,必须使用极为讨厌的isNaN()
console.log(NaN === NaN); // false
console.log(isNaN(NaN)); // true
为改善这类情况,ECMAScript 6规范新增了 Object.is(),这个方法与===很像,但同时也考虑到了上述边界情形。这个方法必须接收两个参数:
console.log(Object.is(true, 1)); // false
console.log(Object.is({}, {})); // false
console.log(Object.is("2", 2)); // false
// 正确的0、-0、+0相等/不等判定
console.log(Object.is(+0, -0)); // false
console.log(Object.is(+0, 0)); // true
console.log(Object.is(-0, 0)); // false
// 正确的NaN相等判定
console.log(Object.is(NaN, NaN)); // true