Introduction
这篇文章主要介绍一下JavaScript中的比较运算符==
。先看几道题,如果你都能答上来,那么可以不用看此文了。
1 | console.log('abc' == String('abc')); |
Difference between String('abc')
and new String('abc')
String(xxx)
是将xxx
转换为字符串,所以它返回的是字符串,而'abc'
原本就是字符串,这里相当于直接返回'abc'
。typeof String(‘abc’)返回的是string
。new String(xxx)
是创建一个字符串对象,其内容是xxx
,所以它返回的是一个对象类型,不是字符串类型。typeof new String(‘abc’)返回的是object
。
How ==
works?
==
采用Loose equality算法,其过程如下:
- 如果两个操作数类型相同,则按如下规则比较:
- Object类型:当两个操作数指向同一个对象时返回
true
,否则返回false
。 - String类型:当两个操作数的字符序列相同,返回
true
。 - Number类型:当两个操作数的数值相同,返回
true
。注意:+0
和-0
被认为是相等的,NaN和任何值都不相等,包括其自身。 - Boolean类型:当两个操作数都是
true
或者都是false
时返回true
。 - BigInt类型:当两个操作数的数值相同,返回
true
。 - Symbol类型:当两个操作数都是相同的Symbol值时返回
true
。
- Object类型:当两个操作数指向同一个对象时返回
- 如果两个操作数类型不同,则按如下规则比较:
- 如果一个操作数是
null
,另一个操作数是undefined
,返回true
。 - 如果一个操作数是
primitive
类型,另一个操作数是Object
类型,将Object
类型转换为primitive
类型(转换规则在此),再按如下规则比较。 - 到这一步时,两个操作数都是
primitive
类型了,按如下规则继续比较。- 如果两个操作数类型相同,按照第1条规则比较。
- 如果一个操作数是
Symbol
类型,但另一个不是,返回false
。 - 如果一个操作数是
Boolean
类型,将其转换为Number
类型(true
-> 1,false
-> 0),继续往下比较。 Number
类型与String
类型比较,将String
类型转换为Number
类型进行比较。转换规则在此。Number
类型与BigInt
类型比较,比较他们的值,如果有一个操作数是+Infinity/-Infinity/NaN
,返回false
。String
类型与BigInt
类型比较,将String
类型转换为BigInt
类型(用BigInt()
转换),若转换失败则返回false
。
- 如果一个操作数是
类型相同时,比较好理解,我们重点梳理一下类型不同时的比较。
- 两个对象类型之间的比较是比较引用地址,也比较简单,无需赘述。
- 一个对象和一个基本类型的比较,会将对象转换为基本类型,然后再比较。
- 两个基本类型之间的比较,其实,最终都会归类到此类比较。
所以,我们重点讨论一下基本类型之间的比较。JS中有7种基本类型,分别是String
, Number
, BigInt
, Boolean
, Symbol
, null
, undefined
。
null
和undefined
之间的比较,返回true
。Symbol
和其他类型之间的比较,都返回false
。
至此,还剩下String
,Number
,BigInt
,Boolean
之间的比较。剩下的这几个类型比较,基本围绕Number
进行。Boolean
和Number
之间的比较,将Boolean
转换为Number
,然后再比较。String
和Number
之间的比较,将String
转换为Number
,然后再比较。Boolean
和String
之间的比较,将他们都转换为Number
然后再比较。String
和BigInt
之间的比较,将String
转换为BigInt
,然后再比较。Number
和BigInt
之间的比较,比较他们的值,如果有一个操作数是+Infinity/-Infinity/NaN
,返回false
。
注意:
Loose Equality
算法满足交换律,即A == B
等价于B == A
。document.all
被视为undefined
.
Examples
以下给出一些采用==
进行比较的例子,我们会给出每个例子的比较规则对应的序号(参考How == works一节
)。
1 | "1" == 1; // true, 2.3.4 |
下面这个例子要注意:
1 | const a = [1, 2, 3]; |
Array.prototype.toString()
方法重写了Object.prototype.toString()
方法,数组转化为字符串时,会执行以下步骤:
- 对数组内每个元素调用
toString()
方法,将其转化为字符串。 - 将这些字符串用逗号连接起来。
- 返回这个字符串。
所以上面的例子就是[1, 2, 3].toString() == "1,2,3"
,所以返回true
。
所以空数组和空字符串之间的比较也是true
。
1 | [] == ""; // true, 2.3.4 |
数组转字符串还有很多细节,详情请看这里:Array.prototype.toString()。
总结
==
比较时,不要老想着转换为Boolean,其实大多数时候是转换为Number- 对象字面量使用
==
比较时,一定是false
new String(...)
和String(...)
完全不同,前者是创建String对象,后者是将...
转换为字符串。