阅读本篇内容时建议先阅读
我们通常认为“==
检查值是否相等,===
检查值和类型是否相等”。这样听起来蛮有道理,然而并不准确。正确的理解应该是:“==
允许在相等比较中进行强制类型转换,而===
不允许”。
1. 字符串和数字之间的相等比较
var a = 42var b ='42'a == b // truea === b // false复制代码
以上代码很容易理解,因为没有进行强制类型转换,所以a===b
为false
。
而a==b
为宽松相等,如果两个值类型不同,其中一个或者两个会进行强制类型转换。
但具体是怎么转换的?是字符串转换为数字还是数字转换为字符串? ES5规范中这样规定:
(1)如果Type(x)是数字,Type(y)是字符串,则返回 x == ToNumber(y)的结果(2)如果Type(x)是字符串,Type(y)是数字,则返回ToNumber(x) == y的结果复制代码
简单来说就是将字符串转换为数字进行相等比较。
2. 其它类型与布尔值之间的相等比较
var a = '42'var b = truea == b // false复制代码
我们知道'42'
是一个真值,为什么==
的结果不是true
呢?根据ES5规范:
(1)如果Type(x)是布尔类型,则返回ToNumber(x) == y的结果(2)如果Type(y)是布尔类型,则返回x == ToNumber(y)的结果复制代码
简单来说就是将布尔值转换为数字进行相等比较。
具体到这个例子,b
通过ToNumber(b)
转换为数字为1
,变为 '42' == 1
,按照前面的规则'42'
转换为42
,最后变为 42 == 1
,结果为false
。
3. null
和undefined
之间宽松相等
在==
中null和undefined
相等(它们也与其自身相等),除此之外的其它值都不存在这种情况。
var a = nullvar ba == b // truea == null // trueb == null // truea == false // falseb == false // falsea == "" // falseb == "" // falsea == 0 // falseb == 0 // false复制代码
4. 对象和非对象之间的相等比较
关于对象(对象/函数/数组)和标量基本类型(字符串/数字/布尔值)之间相等的比较,ES5规范中如下规定:
(1)如果Type(x)是数字或字符串,Type(y)是对象,则返回 x == ToPrimitive(y)的结果;(2)如果Type(x)是对象,Type(y)是数字和字符串,则返回 ToPrimitive(x) == y的结果。复制代码
这里只提到了数字和字符串,没有布尔值,是因为我们之前介绍过布尔值会被强制转换为数字。 例如:
var a = 42var b = [42]a == b // true复制代码
[42]
首先会调用ToPrimitive
抽象操作转换为'42'
,变成42 == '42'
,然后变成 42 == 42
,返回true
。
5. 比较少见的情况
'0' == null'0' == undefined'0' == false'0' == NaN'0' == '''0' == 0false == nullfalse == undefinedfalse == NaNfalse == 0false == ''false == []false == {}'' == null'' == undefined'' == NaN'' == 0'' == []'' == {}0 == null0 == undefined0 == NaN0 == []0 == {}复制代码
以上相等判断均可通过我们前面的讲解分析出来,答案我就不写了。
下面来看一种极端情况:
[] == ![]复制代码
以上代码的结果是true
还是false
,我们先来分析一下:首先![]
会被转换为false
,变为[] == false
,然后[]
通过ToPrimitive
操作转换为''
,即 '' == false
,然后false
通过ToNumber
转换为0
,变为'' == 0
,最后''
通过ToNumber
转换为0
,变为 0 == 0
,结果为true
。
安全运用隐式强制类型转换
我们要对==
两边的值进行认真推敲,一下两个原则可以让我们有效的避免出错。
- 如果两边的值中有
true
或false
,千万不要使用==
- 如果两边的值中有
[]、''或者0
,尽量不要使用==