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对象,后者是将...转换为字符串。