js 隐式转换

一、ToPrimitive内部运算

1.定义

ToPrimitive运算,它会用于对象转换为原始数据类型,这个运算不只会用在加号运算符,也会用在关系比较或值相等比较的运算中。

语法:ToPrimitive(input, PreferredType?)

input代表代入的值,而PreferredType可以是数字(Number)或字符串(String)其中一种,没有PreferredType默认为数字(Number)。如果input为原始值,则返回原始值;如果为对象,则转换如下:

2.PreferredType为数字(Number)

1).调用对象的valueOf()方法,如果能得到原始数据类型的值,则返回这个值。
2).调用对象的toString()方法,如果能得到原始数据类型的值,则返回这个值。
3).否则,抛出TypeError错误。

3.PreferredType为数字(String)

1).调用对象的toString()方法,如果能得到原始数据类型的值,则返回这个值。
2).调用对象的valueOf()方法,如果能得到原始数据类型的值,则返回这个值。
3).否则,抛出TypeError错误。

4.实例

1)字符串 + 其他原始类型

字符串在加号运算有最高的优先运算,与字符串相加必定是字符串连接运算。所有的其他原始数据类型转为字符串

2)数字 + 其他的非字符串的原始数据类型

数字与其他类型作相加时,除了字符串会优先使用字符串连接运算的,其他都要依照数字为优先,所以除了字符串之外的其他原始数据类型,都要转换为数字来进行数学的相加运算。

3)数字/字符串以外的原始数据类型作加法运算

当数字与字符串以外的,其他原始数据类型直接使用加号运算时,就是转为数字再运算,这与字符串完全无关。

4)[] + []

数组会调用valueOf和toString方法,[] + [] => ‘"" + ""  = ""得到空字符串

5){} + {}

在谷歌浏览器上,{}会调用 valueOf和toString方法得到“[object Object]”,两个相加便得到"[object Object][object Object]"

在Firefox、Edge浏览器则不同,会把前面的{}当做区块语句,略过,剩下+{},进行Number({})运算,相当于Number("[object Object]")运算,最后得出的是NaN

6){} + []

浏览器把{}当做区块语句略过,剩下+[],相当于进行Number([])运算,Number("") => 0

7)[] + {}

相当于"" + "[object Object]" => "[object Object]"

8)Date对象

Date对象调用valueOf和toString方法有些不同(一般对象会先调用valueOf再调用toString),Date对象会先调用toString再调用valueOf

 

二、++[[]][+[]]+[+[]] == 10

首先将++[[]][+[]]+[+[]] 分解为++[[]][+[]] 和 [+[]] 

1.[+[]]

+[],[]是对象,进行toPrimitive运算,调用valueOf方法得到[]不是原始值,然后调用toString方法得到空字符串,转换为数字后得到0,那么[+[]]等于[0]

2.++[[]][+[]]

将++[[]][+[]]变为
var val = [[]][+[]];

++val;

根据上面得出,[+[]]为0,[[]][+[]] => [[]][0] => []

进一步拆分

var val = [];

++val;

因为++时候旧的值要进行 ToNumber() 运算(ToNumber把其他类型按照一定的规则转化成数字类型,也就是类似Number())

所以++val 相当于 val = ToNumber([]) + 1 => 0 + 1 => 1

3.++[[]][+[]]+[+[]]

++[[]][+[]]+[+[]] => 1 + [0] => 1 + "0" => "10"

所以++[[]][+[]]+[+[]]  == 10

 

三、用隐式转换输出"I love you"

(+!![]/+[]+[])[+[]]+([]+{})[~!![]*~!![]*-~!![]-!![]]+(![]+[])[-~!![]]+([]+{})[+!![]]+([][(![]+[])[!![]-~!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]+[])[[]+(+!![]+!![])+(!![]-~!![])]+(!![]+[])[!![]-~!![]]+([]+{})[~!![]*~!![]*-~!![]-!![]]+(+!![]/+[]+[])[-~-~-~-~-~-~!!{}]+([]+{})[+!![]]+(!![]+[])[-~!![]]

转换步骤:

I:(+!![]/+[]+[])[+[]] // 1/0得到 Infinity,加上[]得到"Infinity","Infinity"[0] => "I"

" ": ([]+{})[~!![]*~!![]*-~!![]-!![]] // [] + {} => "[object Object]", "[object Object]"[7] => " "

l:(![]+[])[-~!![]] // "false"[2] => "l"

o: ([]+{})[+!![]] // "[object Object]", "[object Object]"[1] => "o"

v:([][(![]+[])[!![]-~!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]+[])[[]+(+!![]+!![])+(!![]-~!![])] 
1) [][‘sort‘]+[] => "function sort() { [native code] }"
2) "function sort() { [native code] }"[23] => "v"

e:(!![]+[])[!![]-~!![]] // "true"[3] => "e"

" " : ([]+{})[~!![]*~!![]*-~!![]-!![]] // [] + {} => "[object Object]", "[object Object]"[7] => " "
y:(+!![]/+[]+[])[-~-~-~-~-~-~!!{}] // "Infinity"[7] => "y"

o:([]+{})[+!![]] // "[object Object]", "[object Object]"[1] => "o"

u:(!![]+[])[-~!![]] // "true"[2] => "u"

 

四、== 进行对比的转换

1. 对象和布尔值,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字
[] == true; // false []转换为字符串‘‘,然后转换为数字0,true转换为数字1,所以为false
2. 对象和字符串,对象转换为字符串,然后两者进行比较。
[1,2,3] == ‘1,2,3‘ // true [1,2,3]转化为‘1,2,3‘,然后和‘1,2,3‘, 结果为true;
3. 对象和数字,对象先转换为字符串,然后转换为数字,再和数字进行比较。
[1] == 1; // true `对象先转换为字符串再转换为数字,二者再比较 [1] => ‘1‘ => 1 所以结果为true
4. 字符串和数字,字符串转换成数字,二者再比较。
‘1‘ == 1 // true
5. 字符串和布尔值,二者全部转换成数值再比较。
‘1‘ == true; // true
6. 布尔值和数字,布尔转换为数字,二者比较。
true == 1 // true
7.undefined == null //true undefined和null 比较返回true,二者和其他值比较返回false

 

五、运算符的优先级

 

参考:

1.https://segmentfault.com/a/1190000008038678

2.https://segmentfault.com/a/1190000008572281

3.https://www.cnblogs.com/chenmeng0818/p/5954215.html

4.https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence

 

相关文章