宽松相等与严格相等

583 阅读3分钟

前段时间当了一段时间面试工程师,发现很多同学对于宽松相等的问题,基本靠猜。。。能答对的人,也很少能说明原因及其转换规则。所以整理了一下关于宽松相等的转换规则,仅供参考。。。

宽松相等(loose equals)== 和严格相等(strict equals)=== 都用来判断两个值是否“相等”,但是它们之间有一个很重要的区别,特别是在判断条件上。

常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”。听起来蛮有道理,然而还不够准确。很多 JavaScript 的书籍和博客也是这样来解释的,但是很遗憾他们都错了。 正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。”

1.字符串和数字之间的相等比较

规则:

(1) 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。

(2) 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。

即:字符串与数字之间的相等比较,会将字符串转为数字。

var a = 42; 
var b = "42";
a === b;    // false
a == b;     // true  这里会将b转为数字类型再与a做比较

2.其他类型和布尔类型之间的相等比较

规则:

(1) 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果;

(2) 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。

即:与布尔类型的值进行比较,会先将布尔值转为数值类型,再遵循数值类型的转换规则进行比较。

var x = true; 
var y = "42";
x == y; // false  
// 转换过程:x 转换为数字 1; 比较 1 == "42"; "42"转为数字42; 比较 1 == 42; 返回 false

3.null 和 undefined 之间的相等比较

规则:

(1) 如果 x 为 null,y 为 undefined,则结果为 true。

(2) 如果 x 为 undefined,y 为 null,则结果为 true。

记住一句话:在 == 中 null 和 undefined 相等(它们也与其自身相等),除此之外与其它任何值都不相等

var a = null;
var b;
a == b;     // true
a == null;  // true
b == null;  // true
a == false; // false
b == false; // false
a == "";  // false
b == "";  // false
a == 0;   // false
b == 0;   // false

4.对象和非对象之间的相等比较

规则:

(1) 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;

(2) 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。

var a = "abc";
var b = Object( a );
a === b;  // false
a == b; // true 转换过程:b通过ToPromitive进行强制类型转换,并返回标量基本类型值 "abc",与 a 相等。

但有一些值不这样,原因是 == 算法中其他优先级更高的规则。例如:

var a = null;
var b = Object( a );
a == b; // false
var c = undefined;
var d = Object( c );
c == d; // false
var e = NaN;
var f = Object( e );
e == f; // false

5.NaN与任何值都不相等,包括它自己

NaN == NaN // false

6.比较少见的情况

1.[] == ![] 返回true

转换过程:以下代码从上到下为转换过程

[] == ![]
[] == false 
[] == 0
"" == 0
0 == 0 // true

2.定义一个变量a,使a == 1 && a == 2 && a == 3

var i = 1;
Number.prototype.valueOf = function() {
  return i++;
}
var a = new Number();
a == 1 && a == 2 && a == 3

7.以下为常见的比较情况

"0" == null  // false
"0" == undefined // false
"0" == false // true
"0" == NaN // false
"0" == 0 // true
"0" == "" // false
false == null // false
false == undefined // false
false == NaN // false
false == 0 // true
false == "" // true
false == [] // true
false == {} // false
"" == null // false
"" == undefined // false
"" == NaN // false
"" == 0 // true
"" == [] // true
"" == {} //false
0 == null // false
0 == undefined // false
0 == NaN // false
0 == [] // true
0 == {} // false