3. 隐式类型转换陷阱排查
为什么“看起来相等”的表达式会给出意外结果
JavaScript 的隐式类型转换发生在运算符两侧类型不一致时。加号 + 在遇到字符串时优先做拼接,而减号 -、乘号 * 等算术运算符会先把操作数转成数字;== 会按规则做类型转换后再比较,=== 则不做转换。布尔上下文(if、!、&&)会把值转成 true 或 false。这些规则叠加时,很容易产生非预期值。
构造表达式并记录实际结果
下面这段代码把加号、减号、相等比较和布尔上下文集中在一起,运行后逐条打印结果,便于对照上图中的规则定位非预期值。
// 1. 加号:字符串优先拼接
console.log('5' + 2); // "52"
console.log(5 + '2'); // "52"
console.log(5 + 2); // 7
console.log('5' + true); // "5true"
// 2. 减号:强制转数字
console.log('5' - 2); // 3
console.log('5' - '2'); // 3
console.log('abc' - 1); // NaN
console.log(true - 0); // 1
// 3. 相等比较:== 会转换,=== 不转换
console.log('1' == 1); // true
console.log('1' === 1); // false
console.log(null == undefined);// true
console.log(null == 0); // false
console.log([] == false); // true
console.log([] === false); // false
// 4. 布尔上下文
console.log(Boolean('0')); // true
console.log(Boolean('')); // false
console.log(Boolean(0)); // false
console.log(Boolean([])); // true
console.log(Boolean(null)); // false
// 5. 组合陷阱
console.log([] + {}); // "[object Object]"
console.log({} + []); // 0({} 被当作块语句)
console.log(1 + null); // 1
console.log(1 + undefined); // NaN
定位非预期值
把上面结果与预期对照,可以定位到几类典型陷阱:
'5' + 2得到"52"而不是7,因为加号遇到字符串会拼接。'1' == 1得到true,但'1' === 1得到false,说明==做了隐式转换。Boolean('0')得到true,因为非空字符串在布尔上下文中为真。[] == false得到true,因为空数组先转成空字符串,再转成数字 0,与false转成的 0 相等。1 + undefined得到NaN,因为undefined转数字为NaN。
显式转换修正方案
修正的核心是:在运算前明确目标类型,并优先使用 === 替代 ==。
// 修正 1:加号前先转数字
const a = Number('5') + 2; // 7
const b = parseInt('5', 10) + 2; // 7
// 修正 2:比较用 ===
console.log(Number('1') === 1); // true
console.log('1' === String(1)); // true
// 修正 3:布尔判断显式转换
const flag = Boolean('0'); // true,明确知道非空字符串为真
const isEmpty = String('').length === 0; // true,用长度判断更直观
// 修正 4:避免对象参与算术
const arr = [];
const obj = {};
console.log(String(arr) + String(obj)); // "" + "[object Object]"
// 修正 5:null / undefined 单独判断
function isNil(v) {
return v === null || v === undefined;
}
console.log(isNil(null)); // true
console.log(isNil(undefined)); // true
console.log(isNil(0)); // false
排查隐式转换时,先看运算符类型:
+ 看是否有字符串,- * / 看是否能转成有效数字,== 看两侧类型是否一致,布尔上下文看值是否属于假值集合(false、0、""、null、undefined、NaN)。不要依赖
== 的隐式转换来简化代码,尤其在比较 null、undefined、0、"" 和 false 时,容易产生与直觉相反的结果。统一使用 === 并显式转换,可以消除大部分陷阱。