一.定义

  隐式转换是指在JavaScript中,当运算符在运算时,如果两边数据不统一,CPU就无法计算,这时我们编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算。这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换。

二.转换规则

  JavaScript的类型分为基本数据类型和引用数据类型:
  基本数据类型: Undefined、 Null、 String、 Number、 Boolean、(Symbol)->ES6
  引用类型:Object

其直接转换规则如下表:
image.png

而当使用运算符时,两边不同的数据类型的自动转换有一套自己的默认规则,在JavaScript权威指南中这么说明:
image.png

以上面的解释,归类为以下规则:

转为String类型: 
    字符串连接符:+ 
    例:String(1) + "10" = "1" + "10" = "110"
    注:只要加号两边有一边是字符串,则为字符串运算符。

转为Number类型:
    自增自减运算符:++ / --   
    算术运算符:+  -  *  /  %
    关系运算符: >  <  >=  <=  ==  !=  ===  !==
转为Boolean类型:
    逻辑非运算符: !
转为布尔类型成为false的有:
    undefined、null、空字符串、0、-0、NaN
new Number() 和 Number() 是不同的,new Number() 创建了一个Number对象,Number() 将传入的参数转换为数值字面量

再举一些例子:

1 + "true"  // "1true"  若+两边存在一个字符串,将另一个也转为字符串进行字符串拼接  String(1) + "true" = "1true"
1 + true  // 2  这里的 + 是算术运算符 1 + Number(true) = 1 + 1 = 2
1 + undefined  // NaN  这里的 + 是算术运算符 1 + Number(undefined) = 1 + NaN = NaN
1 + null  // 1  这里的 + 是算术运算符 1 + Number(null) = 1 + 0 = 1
1 + "10"  // "110" 这里的 + 是字符串连接符 String(1) + "10" = "1" + "10" = "110"
1 - "10"  // -9 这里的 + 是算术运算符 1 - Number("10") = 1 - 9 = -9
//不要混淆字符串连接符与算术运算符隐式转换规则
"2" > 10  // false  Number(2) > 10 = 2 > 10 = false
"2" > "10"  // true  当两边都是字符串的时候,此时转为number然后比较关系,注意这里并不是按照Number()的形式转为数字,而是按照字符串对应的unicode编码来转成数字,charCodeAt(index)  index为字符下标,默认为0。
"2".charCodeAt(0) > '10'.charCodeAt(0) = 50 > 49 = true
"abc" > "b"  // false  多个字符的时候从左往右依次比较 'a'.charCodeAt(0) = 97  'b'.charCodeAt(0) = 98
"abc" > "aad"  // true 
NaN == NaN  // false 
特殊情况:如果数据类型是undefined或null 得出固定结果
undefined == undefined  // true
undefined == null  // true
null == null  // true
NaN == NaN  // false

三、对象的类型转换

//对象转为布尔值一直为true
//对象
var a = { b: 1 }
a.toString() ⇒  "[object Object]"
a.valueOf() ⇒  {b: 1}
//数组
var a = [1,2,3]
a.toString() ⇒ "1,2,3"
a.valueOf() ⇒  [1, 2, 3]
//函数
var a = function () { b =333; return 111; }
a.toString()  ⇒  "function(){b =333; return 111;}"
a.valueOf()  ⇒ ƒ () { b =333; return 111; }
//日期
var a = new Date()
a.toString() ⇒ "Thu Mar 07 2019 13:48:31 GMT+0800 (中国标准时间)"
a.valueOf() ⇒ 1551937711874
//错误
Error
toString()返回:"Error {错误描述}"
valueOf()返回:错误本身
//正则表达式
var a = new RegExp('^ass[^f]\w?','gi')
a.toString() ⇒ "/^ass[^f]\w?/gi"
a.valueOf() ⇒  "/^ass[^f]\w?/gi"

四、总结和实践

1、 算术运算符(+、-、*、/、++、–、%…)

'+'作为一个双目运算符: 若+两边存在一个字符串,将另一个也转为字符串进行字符串拼接。
其他情况下,不管双目还是单目,都转为数值类型

2、关系运算符(>、<、==、!=…)

===!==:同时对比类型和值,两个都为真才返回真
==!=: 若两边均为对象,对比它们的引用是否相同
!(逻辑非): 将其后变量或表达式转为布尔值
对比字符串:从头至尾扫描逐个比较每个字符的unicode码,直到分出大小
其他情况下,两边均转为数值类型

NaN与任何值都不相同,与任何值比较都返回false
对象类型在运算时进行类型转换都先调用valueOf()方法,再尝试toString()方法
在进行对象字面量(这里说的是JSON格式的对象字面量)运算时要注意,若运算符两边都是字面量,
则将它们都视为对象字面量进行类型转换;
若只有一个字面量时要注意,当这个字面量在首位时,会被当做一个块看待。
{} + {}  =>  "[object Object][object Object]"
{}被当做一个块,相当于执行 ( {}, +[] ),计算的是+[]的结果
{} + []  => 相当于{}; + [],即前面为代码执行掉了,仅剩 +[] => +"" => 0   
{ a: 1 } + []  => 0
{} == []  =>  报错  ({}, ==[])  =>  报错
变量形式运算正常
var a = { q:1 }
a + []  =>  "[object Object]"
[] + a  =>  "[object Object]"
[1,2,3] + []  =>  "1,2,3" + ""  =>  "1,2,3"
[] + {}  =>  "" + "[object Object]"  =>  "[object Object]"
[] == 0  // true      []  =>  ""  =>  0
![] == 0  // true    ![] => false => 0
[] == ![]  // true      []  =>  ""  =>  0    ![] => false => 0
[] == []  // false  比较引用地址
{} == {}  // false  比较引用地址
{} == !{}  //  false    !{}  => false => 0    {} =>  "[object Object]" => Number("[object Object]")  =>  NaN

爱吃鸡蛋饼
55 声望8 粉丝