JavaScript 运算符与类型转换
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
JavaScript 的比较和取值之所以容易出错,多半不是运算符难,而是隐式类型转换在你没注意到的时候发生了。这一篇把规则摊开讲清楚。
== 与 ===
1 == "1" // true (先转换再比较)
1 === "1" // false (类型不同直接不相等)
==(宽松相等):类型不同时先做隐式转换再比较。===(严格相等):类型不同直接返回false,不做转换。
结论:一律用 ===,只在确实需要「null 和 undefined 视为等价」时用 == null 这种写法。
== 的转换规则复杂到不建议记忆,看几个真实结果就够了:
"" == 0 // true
"0" == 0 // true
false == "0" // true
null == 0 // false
null == undefined // true
[] == false // true
truthy 与 falsy
需要布尔值的地方(if、&&、||、!),JavaScript 会把值转成布尔。只有下面 8 个值是 falsy,其余全是 truthy:
false, 0, -0, 0n, "", null, undefined, NaN
注意其中的反直觉项:
if ("0") console.log("执行"); // 执行:非空字符串是 truthy
if ([]) console.log("执行"); // 执行:空数组是 truthy
if ({}) console.log("执行"); // 执行:空对象是 truthy
if (" ") console.log("执行"); // 执行:空格不是空字符串
判断「用户有没有输入」时不要写 if (str),因为 "0" 会误判为空。明确判断:if (str.length > 0)。
算术运算符的隐式转换
"3" - 1 // 2 减号只做数值运算,字符串被转成数字
"3" + 1 // "31" 加号遇到字符串优先拼接
3 + true // 4 true 转成 1
"6" * "2" // 12 乘除取模都会转数字
10 / "a" // NaN
NaN 的特殊性
NaN(Not a Number)表示「算出来不是合法数字」,它不等于任何值,包括自己:
NaN === NaN // false
Number.isNaN(NaN) // true 推荐
isNaN("abc") // true 会先转类型,容易误判
Number.isNaN("abc") // false 只有真正的 NaN 才为 true
检测 NaN 用 Number.isNaN()。
逻辑运算符的真实返回值
&& 和 || 不返回布尔值,它们返回决定结果的那个操作数:
const a = 0 || "默认"; // "默认"(0 是 falsy,取右边)
const b = "有值" || "默认"; // "有值"
const c = null && "不执行"; // null(左边 falsy,直接返回左边)
?? 与 || 的区别(重要)
两者都用来兜底,但判断条件不同:
const count = 0;
count || 10 // 10 0 是 falsy,被替换掉了
count ?? 10 // 0 0 是有效值,保留
const text = "";
text || "匿名" // "匿名"
text ?? "匿名" // "" 空字符串是有效值,保留
??(空值合并)只在值为 null 或 undefined 时兜底;|| 在所有 falsy 值上兜底。
配置读取、默认值填充应该用 ??,避免把 0、""、false 这些合法值误替换掉。
function greet(name) {
const who = name ?? "匿名";
console.log(`你好,${who}`);
}
注意:?? 不能和 ||、&& 直接混用,必须加括号:
a ?? b || c // SyntaxError
(a ?? b) || c // 正确
可选链 ?. 与空值赋值 ??=
访问深层属性时,中间任何一层是 null / undefined 都会抛错:
const city = user.address.city; // address 为空时抛 TypeError
const city = user?.address?.city; // 安全,短路返回 undefined
??= 表示「仅当左侧为 null / undefined 时赋值」:
const config = { retries: 0 };
config.retries ??= 3; // 0 是有效值,不覆盖
config.timeout ??= 5000; // undefined,赋值为 5000
console.log(config); // { retries: 0, timeout: 5000 }
显式类型转换
依赖隐式转换是可读性杀手,需要转换时写清楚:
Number("42") // 42
Number("42abc") // NaN(parseInt 会得到 42,注意区别)
parseInt("42px", 10) // 42,忽略尾部非数字字符,务必传第二个参数 10
String(42) // "42"
Boolean("") // false
常见错误与注意事项
- 用
==比较导致"" == 0成立:改用===。 if (value)判断数字是否为 0:0是 falsy,会被跳过。判断存在性用value !== undefined。- 把
NaN当 falsy 处理并兜底:NaN确实是 falsy,但它往往说明上游计算出错,应该排查而不是给默认值。 ||覆盖了0和"":改成??。- 链式访问深层属性不判空:用
?.,但仍要处理最终是undefined的情况。
小结
- 比较用
===,兜底用??,深层访问用?.。 - 只有 8 个 falsy 值;
[]、{}、"0"、" "都是 truthy。 &&/||返回操作数本身,不是布尔值。- 检测
NaN用Number.isNaN()。