JavaScript 加号运算符的作用
作用 | 示例 | 结果 |
1, 相加数值 | 7 + 7 | 数值 14 |
2, 连接字符串 | ‘7’ + ‘7’ | 字符串 ’77’ |
3, 转换操作数为数值 | + ‘7’ | 数值 7 |
1, 两个操作数
有两个操作数 a + b 时,会相加数值或者连接字符串。
在 JavaScript 中对两个操作数进行 + 运算时,可能会触发将其转换为原始值(ToPrimitive)、转换为数字(ToNumber)、转换为字符串(ToString)。
ToPrimitive 转换顺序:
- 若操作数是原始值,则返回它;
- 若它的 valueOf() 的返回值是原始值,则返回 valueOf() 的返回值;
- 若它的 toString() 的返回值是原始值,则返回 toString() 的返回值;
- 抛出 TypeError 错误。
ToPrimitive 的转换顺序并不是完全绝对的,其中第 2 步和第 3 步可以调换,目前只有 Date 对象是在转换为原始值时是先调用 toString,再调用 toValueOf,其余均符合上面的转换顺序。
JavaScript 的原始值包括:undefined、null、布尔值、数字、字符串。
a + b
把操作数 a、b 转换为原始值还不能马上进行 + 运算,还需要再进行 ToNumber 或者 ToString 转换为相同类型。
ToNumber 转换顺序:
- undefined => NaN
- null => 0
- true => 1
- false => 0
- 数字 => 自身
- 字符串 => 转换为数字,例如 “2.2” 转换为 2.2、”2.2a” 转换为 NaN
字符串转换为数字可以参考(实际中不是像下面这样做的,但结果一致):
"2.2" / 1 // 2.2 "2.a" / 1 // NaN
ToString 转换书序:
- undefined => “undefined”
- null => “null”
- true => “true”
- false => “false”
- 数字 => 转换为字符串,例如 1 转换为 “1”、NaN 转换为 “NaN”
- 字符串 => 自身
ToString 很好理解,简单地看就是在原来非字符串的两侧加上引号。
当 a + b 时,先将 a、b 转换为原始值,如果其中有一个是字符串,则将另外一个也转换为字符串,连接两个字符串并返回;将两个操作数转换为数字,相加并返回。
var a = true; var b = false; a + b // ? a 原始值是 true, b 原始值是 false, 均不是字符串, 因此是 1 var a = 1; var b = [2]; a + b // ? a 原始值是 1, b 原始值是 "2", 因此是 "12" var a = 1; var b = new Date; a + b // ?
2, 一个操作数
只有一个操作数时,会转换操作数为数值。这个比较好理解,可以按照上面提到的除以 1,结果其实就是操作数除以 1 或者乘以 1。
3, 看似两个操作数
var a = {}; var b = []; a + b // 根据转换为原始值的规则, 结果是 "[object Object]" {} + [] // 结果是 0, 为什么呢
因为 JavaScript 解释器(一般浏览器环境)会将第一行的 {} 代码块忽略掉,因此如下的代码看似两个操作数,实际在浏览器中是一个,即只有 + []。
在 NodeJS 里面就不会将第一行的 {} 代码块忽略掉,其执行结果是 “[object Object]”。
另外,关于转换为原始值中出现 TypeError,可以进行简单的重现:
var a = { toString: function() { return []; }, valueOf: function() { return []; } }; var b = null; a + b // 将会看到 TypeError: Cannot convert object to primitive value