V8会提供一个toPrimitive方法,分别对参与加运算的左右项进行处理,得到值后赋给其原生值。 toPrimitive方法流程如下:
- 先检测对象是否有valueOf()方法,如果有的话,调用其valueOf方法,如果结果是基本类型值,返回结果。
- 没有valueOf()方法,或者valueOf()返回的不是基本类型值,调用toString()方法, 如果结果是基本类型值,返回结果。
- 上面两个方法都不存在或者都没有返回基本类型值,会触发TypeError错误。
经过toPrimitive处理后,分别判断左右对象的类型。
- 如果左右对象中有一个是字符串(typeof结果为’string‘),则将左右都使用toString()转化为字符串,然后拼接。
- 如果左右都不是字符串,则都使用Number强转为数字,然后进行加法计算。
举个例子:
1 + ’2‘
先调用toPrimitive(),左侧的 1 调用valueOf()方法后,得到 1, 是Number,是基本数据类型;右侧调用valueOf()方法后,返回'2',是字符串,是基本数据类型。
左右两侧存在字符串类型,所以都转化为字符串进行拼接,结果为 '12'
。
再举一个例子:
比如下面表达式的结果是什么?
['a','b','c','d', 'e'] + 1
首先调用toPrimitive(), 左侧是一个数组, 调用valueOf()方法后返回的依然是数组,不是基本数据类型。
['a','b','c','d', 'e'].valueOf() // ['a','b','c','d', 'e']
然后调用toString(),得到字符串,是基本类型,
['a','b','c','d', 'e'].toString() // 'a,b,c,d,e'
右侧自然是valueOf()直接返回数字1,所以相当于运算
'a,b,c,d,e' + 1
结果是'a,b,c,d,e1'
再举一个例子
var a = {
toString() {
return "200"
},
valueOf() {
return 100
}
}
a+"3"
在使用toPrimitive()处理左右值的时候,a因为有valueOf()方法,所以直接调用返回100,相当于计算
100 + ”3“
结果是'1003'