先来一波运算符的优先级 :

javaScript运算符优先级

原始类型之间的隐式转换

js有五种原始值[‘Null’,’Undefined’,’String’,’Boolean’,’Number’]
原始类型的值 转换为数值 转换为字符串 转换为布尔
false 0 “false” false
true 1 “true” true
0 0 “0” false
1 1 “1” true
“0” 0 “0” false
“1” 1 “1” true
NaN NaN “NaN” false
infinity infinity “infinity” true
-infinity -infinity “-infinity” true
“” 0 “” true
“name” NaN “name” true
null 0 “null” false
undefined NaN “undefined” false
引用类型的值 转换为数值 转换为字符串 转换为布尔
[] 0 “” true
[10] 10 “10” true
[10,20] NaN “10,20” true
{} NaN “[Object Object]” true

“+” 号的运算规则

js在加法运算的时候会把运算对象转换为原始值然后进行运算

1.使用ToPrimitive转换为原始值

JS引擎内部转换为原始值时,都会调用ToPrimitive函数转换,然后在ToPrimitive函数内部会调用valueOf()toString()方法进行转换

转换规则如下:

如果运算值不是Date类型,那么在运算转换的时候,

1. 如果obj为原始值,直接返回;
2. 否则调用 obj.valueOf(),如果执行结果是原始值,返回之;
3. 否则调用 obj.toString(),如果执行结果是原始值,返回之;
4. 否则抛异常。

如果是Date类型的话,将上面的第2步和第3步调换,即:

1. 如果obj为原始值,直接返回;
2. 否则调用 obj.toString(),如果执行结果是原始值,返回之;
3. 否则调用 obj.valueOf(),如果执行结果是原始值,返回之;
4. 否则抛异常。
toString 用来返回对象的字符串表示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var obj = {
name: 'obj'
};
console.log(obj.toString()); // "[Object Object]"

var obj1 = {};
console.log(obj1.toString()); // "[Object Object]"

var arr = [10];
console.log(arr.toString()); // "10"

var arr1 = [];
console.log(arr1.toString()); // ""

var date = new Date();
console.log(date.toString()); // Wed Apr 11 2018 11:52:55 GMT+0800 (中国标准时间)
valueOf 用来返回对象的原始值,可能是字符串、数值或bool值等,看具体的对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var obj = {
name: 'obj'
};
console.log(obj.valueOf()); // {name: "obj"}

var obj1 = {};
console.log(obj1.valueOf()); // {}

var arr = [10];
console.log(arr.valueOf()); // [10]

var arr1 = [];
console.log(arr1.valueOf()); // []

var date = new Date();
console.log(date.valueOf()); // 1523419204170

2.原始值之间的隐式转换

1.如果在一端出现字符串类型的值时,转换为字符串进行运算
2.其他情况转换为数值进行运算

上面的代码以加号分割成左右俩部分

左: ++[[]][+[]]
右: [+[]]
温馨提示:
1
2
3
4
[] :         
转换成字符串会转换为""
转换为数字会转换为0
转换为布尔值会转换为true

注意点 几种强制转换类型

1
2
3
+[] 前面有加号会把运算对象转换为数字 
+new Date 转换成时间戳
! 会把运算对象转换为bool值
左边细分: ++[[]] 和 [+[]]
  1. ([]优先级高于 ++ 先算[]里的)
  2. +[] 前面有+会转换为数字 得 [0]
  3. 左边最终为 ++[[]][0] 取出数组[[]]的第一个元素累加即:++[]
  4. ++[] 进行累计运算 [] 转换为 数值 0 即 ++0;
右边细分:+[] 转换为数字 得 0
  1. 右边最终为 [0]
  2. 最终的表达式就成了 ++0+[0]
  3. 运算的时候,对[0]使用valueOf()方法,返回的不是原始值,继续调用toString方法得到”0”,然后在进行 ++0+”0” , ++ 优先于 + 最终结果得到的就是 1+ “0” =”10”;

总结

以上我们可以得出一个结论:
js在进行加法运算的时候
1.首先会对加号俩边不是原始值的数据进行ToPrimitive转换为原始值
2.在俩边都是原始值后,会进行原始值之间适当的隐式转换,再进行运算

推荐github上一个repo jsfuck 各种隐式转换的情况
参考链接