按照正常的逻辑来说,我们判断两个值是否相等会遵循以下规则:
但是我看下面一组值:
[]==0 //true []==false //true []==!{} //true [10]==10 //true '0'==false //true ''==0 //true undefined==null //true !null==true //true
居然没有按照我们的剧本走,那它比较规则又是什么?下面我就来分析一波。
“==”的比较规则
首先我们先去ECMAScript5.1中文版( ... )找一下“==”的比较规则,如下:
1.若Type(x)与Type(y)相同, 则
a.若Type(x)为Undefined, 返回true。
b.若Type(x)为Null, 返回true。
c.若Type(x)为Number, 则
i.若x为NaN, 返回false。
ii.若y为NaN, 返回false。
iii.若x与y为相等数值, 返回true。
iv.若x 为 +0 且 y为−0, 返回true。
v.若x 为 −0 且 y为+0, 返回true。
vi返回false。
d.若Type(x)为String, 则当x和y为完全相同的字符序列(长度相等且相同字符在相同位置)时返回true。 否则, 返回false。
e.若Type(x)为Boolean, 当x和y为同为true或者同为false时返回true。 否则, 返回false。
f.当x和y为引用同一对象时返回true。否则,返回false。
2.若x为null且y为undefined, 返回true。
3.若x为undefined且y为null, 返回true。
4.若Type(x) 为 Number 且 Type(y)为String, 返回comparison x == ToNumber(y)的结果。
5.若Type(x) 为 String 且 Type(y)为Number,返回比较ToNumber(x) == y的结果。
6.若Type(x)为Boolean, 返回比较ToNumber(x) == y的结果。
7.若Type(y)为Boolean, 返回比较x == ToNumber(y)的结果。
8.若Type(x)为String或Number,且Type(y)为Object,返回比较x == ToPrimitive(y)的结果。
9.若Type(x)为Object且Type(y)为String或Number, 返回比较ToPrimitive(x) == y的结果。
10.返回 false
看完ECMAScript5.1中文版的介绍之后,相信很多小伙伴的心情应该是这样的:
别看上面说的有点花里胡哨的,其实我们可以用很简单的话来总结出来。由于本篇文章核心是“==”是如何进行类型转换,我就总结一下类型不同的情况下“==”是如何比较的。
当数据类型为Boolean类型或者String类型时,比较时需要转换成Number类型。
当数据类型为引用类型时,需要转换成原始数据类型。当转换后的原始数据类型为Boolean类型或者String类型,则继续转换成Number类型。
undefined和null跟任何值在“==”下都返回false,但二者在“==”下返回true。
具体流程图如下:
备注:
Javascript的数据类型可以分为以下两种:
原始数据类型(null、undefined、Number、String、Boolean、Symbol(Es6才引入的))
引用类型 (Object)
Boolean类型、String类型转换成Number类型的规则(ToNumber)
Boolean类型
Boolean
Number
true
1
false
0
String类型
标准的数字格式
如果是标准的数字格式,转换成Number类型相比不用多说,比如下面这几个栗子🌰:
"123" => 123 "12.34" => 12.34 "0.12" => 0.12 "-12.34" => -12.34
非标准的数字格式
但是如果是非标准的数据格式,要分两种情况来考虑:
第一种:只包含数字并且最多只有1个点。
第二种:包含非数字以及含有多个1个点。
只包含数字并且最多只有1个点
这种情况下会首先进行补0和去0的操作,下面看几个栗子🌰:
"01234" => 1234 ".1" => 0.1 "12." => 12 "1.000" => 1 "-02.30" => -2.3
包含非数字以及含有多个1个点
这种情况下统统返回NaN,意为“Not a Number”,这里我们要注意一下,NaN还是Number类型,下面看几个栗子🌰:
"123aa4" => NaN "哈喽,DD" => NaN typeof NaN => "numer"
引用类型转换成原始数据类型的规则(ToPrimitive)
在介绍转换规则之前,首先我们我们介绍一下引用类型都带有的两个方法:
Object.prototype.toString
Object.prototype.valueOf
这二者都可以将引用类型转换成原始数据类型,接下来我们对二者做一个详细的介绍:
Object.prototype.toString
MDN是这样解释的:
The toString() method returns a string representing the object.(toString()这个方法返回一个代表这个对象的字符串)
举个栗子🌰:
const obj = {} console.log(String(obj)) //"[object Object]" obj.toString = function(){ return 'Hello,Teacher Cang!' } console.log(String(obj)) //"Hello,Teacher Cang!"
Object.prototype.valueOf
MDN是这样解释的:
The valueOf() method returns the primitive value of the specified object.( valueOf()这个方法返回这个对象的原始数据值)
举个栗子🌰:
const obj = {} console.log(Number(obj)) //NaN obj.valueOf = function(){ return 12345; } console.log(Number(obj)) //12345
valueOf和toString的优先级
关于这二者的优先级,在不同的情况下有着不同的优先级,下面我们根据不同情况介绍一下。
ToNumber
看个栗子🌰: