JavaScript V8处理加运算

785 阅读2分钟

V8会提供一个toPrimitive方法,分别对参与加运算的左右项进行处理,得到值后赋给其原生值。 toPrimitive方法流程如下:

  1. 先检测对象是否有valueOf()方法,如果有的话,调用其valueOf方法,如果结果是基本类型值,返回结果。
  2. 没有valueOf()方法,或者valueOf()返回的不是基本类型值,调用toString()方法, 如果结果是基本类型值,返回结果。
  3. 上面两个方法都不存在或者都没有返回基本类型值,会触发TypeError错误。

经过toPrimitive处理后,分别判断左右对象的类型。

  1. 如果左右对象中有一个是字符串(typeof结果为’string‘),则将左右都使用toString()转化为字符串,然后拼接。
  2. 如果左右都不是字符串,则都使用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'