加号运算符(+)在JavaScript中根据操作数类型自动选择数值相加或字符串拼接:任一操作数为字符串则全部转为字符串拼接;否则全部转为数字相加,失败则得NaN;对象会按valueOf()→toString()顺序转换。

加号运算符(+)是隐式转换最典型、也最容易被忽视的触发点——它既可能做数值相加,也可能做字符串拼接,具体走哪条路,完全取决于操作数的类型组合,而不是程序员的“本意”。
看操作数中是否含字符串
只要 任一操作数是字符串,整个表达式就进入字符串拼接路径,其余操作数会被隐式转为字符串再连接:
-
1 + "2"→"12"(数字1转成字符串"1") -
true + "hello"→"truehello"(布尔值true转成字符串"true") -
null + "end"→"nullend"(null转成字符串"null") -
[1, 2] + "x"→"1,2x"(数组先调用.toString()得"1,2")
当两个操作数都不是字符串时,默认尝试数值计算
此时 JavaScript 会把所有操作数转为数字再相加,转换失败则得 NaN:
-
1 + true→2(true → 1) -
"1" + 2不走这条路,因为"1"是字符串 → 实际结果是"12" -
1 + []→1([] → "" → "1" → 但注意:这里其实是1 + ""→ 字符串拼接得"1";若想强制数值相加,应写1 + +[]或1 + Number([]))
对象和原始值混合时,转换逻辑更隐蔽
遇到对象(如{}、[]、自定义对象),+ 运算符会按固定顺序尝试转换:
- 先调用
valueOf(),若返回原始值就用它 - 否则调用
toString(),再用其返回值 - 若两者都返回非原始值(极少见),抛出 TypeError
例如:{} + [] 在多数引擎中实际被解析为 +[].toString() → +"" → 0;而 ({}) + [] 则是 "[object Object]" + "" → "[object Object]"。括号改变分组,结果完全不同。
对比其他语言能帮你快速定位问题
C# 和 C++ 中的 + 不具备这种二义性:C# 要求明确类型一致才允许加法,字符串拼接需至少一个 string;C++ 的 + 对内置类型严格按类型规则运算,不会自动转字符串。所以当你在 JS 里看到 1 + "2" 得到 "12",这不是“智能”,而是设计选择带来的隐式转换行为。











