隐式类型转换出现在==中,全等号===不存在隐式类型转换,另外还要了解一点,JavaScript中有三种原始类型(primitive value),分别是NumberStringBoolean,隐式类型转换的最终结果就将双等号两边的数据转换成原始类型然后再进行比较。

隐式类型转换步骤

1、首先看双等号前后有没有NaN,如果有,则一律返回NaN

2、再看双等号前后有没有布尔值,有布尔值就将布尔值转换成数字。(true为1,false为0);

3、然后再看等号两边有没有字符串,有字符串又分为三种情况

  • 另外一边是对象,对象使用toString()或者valueOf()进行转换,如果valueOf()返回的是原始类型的值,则采用该值进行比较;如果返回的不是原始类型的值,则尝试使用toString()的返回值,如果toString()的返回值是原始类型,则使用该值进行比较,否则,抛出错误:

    Uncaught TypeError: Cannot convert object to primitive value

  • 另外一边是数字,字符串转成数字,这个时候字符串转成数字规则如下:

    ​ 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值;

    ​ 如果字符串中包含有效的浮点格式,则将其转换为对应的浮点数值;

    ​ 如果字符串中包含有效的十六进制格式,则将其转换为相同大小的十进制整数值;

    ​ 如果字符串是空的(不包含任何字符),则将其转换为0;

    ​ 如果字符串中包含上述格式之外的字符,则将其转换为NaN​。

  • 另外一边是字符串,直接比较;

  • 其他返回false

4、如果一边是数字,另一边是对象,对象使用valueOf()或者toString()进行比较

​ 如果vlaueOf存在,且返回原始类型数据,返回valueOf结果;

​ 如果toString存在,且返回原始类型数据,返回toString结果

​ 以上情况都不存在,报错。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a={
toString:function(){
console.log('调用了 a.toString');
return {};
},
valueOf:function(){
console.log('调用了 a.valueOf');
return {};
}
}

a+1;
//调用了a.valueOf
//调用了a.toString
Uncaught TypeError: Cannot convert object to primitive value

5、null、undefined不会进行类型转换,但是有如下比较结果

1
2
null == undefined;// true
null === undefined; // false

看下面一个题目

1
2
3
4
5
6
7
8
9
10
11
12
[] == ![]; //true
/*
右边是逻辑判断,所以先转成boolean,
[] == !true
[] == false
将布尔值转成数字
[] == 0
左边不是原始类型,尝试把左边转成原始类型,变成
'' == 0
左边转成数字
0 == 0
*/

综上,我的理解:

​ 在比较的第一步,如果其中一方为原始类型数据,则将另一方转成原始类型,这一步规则如下:

1
2
number == obj;//obj先调用valueOf再调用toString,如果结果都不满意,报错
string == obj;//obj先调用toString再调用valueOf,如果结果都不满意,报错

​ 接下来:1、如果双方都是字符串,则直接比较 ;

​ 2、如果双方都是boolean则直接比较;

​ 3、如果双方都是数字,则直接比较;

​ 4、如果有一方是数字,将另一方转成数字进行比较;

​ 5、如果一方为boolean一方为String,则将两者均转为数字再进行比较

多说一点:对象({})和布尔进行双等比较,总是返回false,但是Boolean({})返回的是true

参考资料:

JavaScript对象转化之toString、valueOf

JavaScript中的相等性判断

多说一句,相等操作符==应尽量少的使用,全等操作符的结果更容易预测,并且因为没有隐式转换,全等比较的操作会更快。