宽松相等(==)和严格相等(===)都是用来判断两个值是否“相等”,但是它们又一个很重要的区别。
== 允许在相等比较中进行强制类型转换,而 === 不允许。
== 和 === 都会检查操作数的类型。区别在于操作数类型不同时它们的处理方式不同。
抽象相等
如果两个值的类型相同,就今比较它们是否相等。
console.log(42 == 42); // true
console.log("abc" == "abcd"); // false
注意
- NaN 不等于 NaN
- +0 等于 -0
对象(包括函数和数组)的宽松相等 ==。两个对象指向同一个值时,视为相等,不会发生强制类型转换。
var obj = {
value: 1,
toString: function(){
return obj.value;
}
};
var str = obj;
console.log(str == obj); // true
var arr = [1, 2];
var arr2 = arr;
console.log(arr == arr2); // true
== 在比较两个不同类型时会发生隐式强制类型转换,会将其中之一或两者都转换为相同的类型后再进行比较。
宽松不想等 != 就是 == 的相反值,!== 同理。
字符串和数字之间的相等比较。
var a = 42;
var b = '42';
console.log(a === b); // false
console.log(a == b); // true
// == 比较时,将 b 转化为 数字 42,再与 a 进行比较
转换定义:
- 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
- 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。
其他类型和布尔类型之间的相等比较。
var a = '42';
var b = true;
console.log(a == b); // false
// == 比较时,将 a 转换为数字 42, 将 b 转换为数字 1
// 42 == 1 结果为 false
转换定义:
- 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果。
- 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
// 所以我们在想要判断 a 为真值时可以这样操作
var a = '42'
if (a) {}
// 推荐
if (!!a) {}
if (Boonlean(a)) {}
null 和 undefined 之间的相等比较。
转换定义:
- 如果 x 为 null,y 为 undefined,则结果为 true。
- 如果 x 为 undefined,y 为 null,则结果为 true。
在 == 中,null 和 endefined 相等(它们也和自身相等), 初次之外其他值都不存在这种情况。
var a = null;
var b;
console.log(a == b); // true
console.log(a == null); // true
console.log(b == null); // true
console.log(a == false); // false
console.log(b == false); // false
console.log(a == ''); // false
console.log(b == ''); // false
console.log(a == 0); // false
console.log(b == 0); // false
null 和 undefined 之间的强制类型转换是安全可靠的。例子中除 null 和 undefined 以外的其他值均无法得到 true 的结果。
对象和非对象之间的比较。
关于对象(对象 / 函数 / 数组)和标量基本类型(字符串 / 数字 / 布尔值)之间相比较
转换定义:
- 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPromitive(y) 的结果。
- 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
var a = 40;
var b = [40];
console.log(a == b); // true
// b 数组 通过 ToPromitive 抽象操作(toString, valueOf)强制转化为 40 进行比较
var str = 'abc';
var str2 = Object(a);
console.log(str === str2); // false
console.log(str == str2); // true
// str2 通过 ToPromitive 进行强制类型的转换,返回字符串 'abc'
// 所以 str == str2
有些值是这样,原因是 == 算法中其他优先级更高的规则。
var a = null;
var b = Object(a); // b = {}
console.log(a == b); // false
var c;
var d = Object(c); // d = {}
console.log(c == d); // false
var e = NaN;
var f = Object(e); // Number(NaN)
console.log(e == f); // false
特例 - 返回其他数字
Number.prototype.valueOf = function() {
return 3;
}
console.log(new Number(2) == 3) // true
// new Number(2) 强制类型转换会调用 valueOf 方法,也就是返回 3
// 3 == 3 结果为 true
// 还有一种 a == 2 && a == 3 结果为true
var i = 1;
Number.prototype.valueOf = function() {
return ++i;
}
var a = new Number(111);
if (a == 2 && a == 3) {
console.log('yep, this happened!')
}
特例 - 假值的相等比较
// 常规和非常规的情况
"0" == null // false
"0" == undefined // false
"0" == NaN // false
"0" == false // true - "0"转化为数字 0,false 转化为数字 0,0 == 0
"0" == 0 // true - "0"转化为数字 0,0 == 0
"0" == "" // false
false == null // false
false == undefined // false
false == NaN // false NaN 与任何值都不相等,包括自己
false == 0 // true - false 转化为数字 0, 0 == 0
false == "" // true
false == [] // true
false == {} // false
"" == null // false
"" == undefined // false
"" == NaN // false
"" == 0 // false
"" == [] // true
"" == {} // false
0 == null // false
0 == undefined // false
0 == NaN // false
0 == [] // true
0 == {} // false