在 JavaScript 中,不同类型的值进行运算时,引擎会按照既定规则自动转换类型。其中加法运算和逻辑运算的转换规则最容易让人踩坑,因为它们的隐蔽性强,且日常使用频率极高。
加法运算符(+)的类型转换
加法运算符是 JavaScript 中最“忙”的运算符——它既是算术加法,也是字符串连接符。引擎在遇到 + 时,会按以下优先级决定行为:
- 如果任一操作数是字符串,则将另一个操作数也转换为字符串,然后拼接。
- 否则,两个操作数都转换为数字,执行算术加法。
1 + 2 // 3,纯数字加法
'1' + 2 // '12',字符串拼接,2 被转为 '2'
1 + '2' // '12',同上
true + 1 // 2,true 转为数字 1
false + 1 // 1,false 转为数字 0
null + 1 // 1,null 转为数字 0
undefined + 1 // NaN,undefined 转为数字是 NaN
[] + 1 // '1',[] 转为空字符串 '',再与 1 拼接
[1,2] + 3 // '1,23',[1,2] 转为 '1,2',再拼接 3
{} + 1 // 结果可能是 1 或 '[object Object]1',取决于上下文
需要特别注意的两个陷阱:
- 数组与对象在转换时,会先调用它们的
toString()方法。空数组变成"",所以[] + 1等价于"" + 1,结果为字符串"1"。对象转为"[object Object]"。 {}在语句开头可能会被解析为代码块而不是空对象,导致诡异行为,建议始终用括号包裹({})来明确意图。
实用原则:
- 不确定类型时,显式转换,用
String()、Number()或toString(),不要依赖隐式转换。 - 用模板字符串代替
+拼接,可读性更好:`${a}${b}优于a + b`。
逻辑运算符的类型转换
逻辑运算符 &&、||、! 常用于条件判断,但它们并不总是返回布尔值。
逻辑非 !
- 先将操作数转换为布尔值,然后取反。
- 转换规则:
false、0、''、null、undefined、NaN视为假值(falsy),其余为真值(truthy)。
!0 // true
!'' // true
!null // true
!undefined // true
!NaN // true
!1 // false
!'hello' // false
逻辑与 && 和逻辑或 ||
它们采用短路求值,并且返回的是操作数本身,而不是布尔值:
A && B:如果 A 是 falsy,直接返回 A(不评估 B);否则返回 B。A || B:如果 A 是 truthy,直接返回 A;否则返回 B。
0 && 'hello' // 0,因为 0 是 falsy,返回 0
1 && 'hello' // 'hello',1 是 truthy,返回右侧值
'' || 'default' // 'default',空字符串是 falsy,返回右侧
'name' || 'guest' // 'name',非空字符串是 truthy,直接返回
这种特性常被用于提供默认值或条件执行:
const name = inputName || '匿名用户'; // 如果 inputName 为空,用后备值
isLogged && showDashboard(); // 只有 isLogged 为真时才执行函数
注意 || 默认值的缺陷:如果 inputName 是 0 或空字符串 ''(合法的假值),|| 会跳过它而使用默认值,这可能不是你想要的结果。此时使用 空值合并运算符 ?? 更安全,它仅在左侧为 null 或 undefined 时才取右侧值。
0 || 100 // 100,可能不合理
0 ?? 100 // 0,更符合预期
'' ?? '默认' // '',而 '' || '默认' 返回 '默认'
常见易错点:在 if 语句中,条件会被自动转为布尔值,所以习惯了 if (obj) 的写法后,容易误以为 && 和 || 也返回布尔值,导致后续使用时出现类型意外。例如:
const result = isReady && fetchData(); // result 可能是 false 或 fetchData 的返回值
if (result === true) { ... } // 条件可能永远不成立,因为 fetchData 返回的可能不是 true
记住三个核心规则:
- 加法遇字符串则拼接,否则转数字相加。
- 逻辑非一定返回布尔值,逻辑与/或返回原始操作数。
- 判断假值时,明确是“假值集合”(6个值)还是只针对
null/undefined,选择合适的运算符。