运算符与类型转换
这一课你将能做到
- 正确使用
=== 做相等判断,并能说明为何业务代码少用 ==
- 分清
|| 与 ?? 的差别,知道 0 / "" 何时该保留
- 在表单拿到的字符串和数字之间做显式转换,并用
Number.isFinite 校验
为什么要学
页面输入框拿到的常常是字符串。
你写 age > 18,若 age 是 "20" 有时能比,有时和 + 搅在一起就翻车。
最容易懵的就是「隐式转换」——JS 偷偷帮你改类型。
原则:能明说就明说,少靠偷偷转换。
这一课练的是「看清类型再运算」,避免后面写业务时被 == 和 || 坑。
先建立图像
| 符号 | 人话 |
|---|
+ - * / % | 加减乘除、取余 |
=== !== | 严格相等 / 不等(看值和类型) |
== != | 宽松相等(会转换类型,易坑) |
&& || | 并且 / 或者(还有短路特性) |
?? | 仅当左边是 null/undefined 时用右边 |
? : | 三元:条件成立取前,否则取后 |
输入框.value ──► 几乎总是 string
要做数学 / 比大小 ──► 先 Number(...) 或 parseInt(..., 10)
要判相等 ──► 默认 ===
要给默认值 ──► 0 也合法时用 ??,不要无脑 ||
跟着做
步骤 1:加法的两种脸
控制台:
1 + 2; // 3 —— 数字相加
"1" + 2; // "12" —— 有字符串时,+ 更像拼接
Number("1") + 2; // 3 —— 先转换成数字再加
"10" - 1; // 9 —— 减号会尝试转数字(别依赖这种「碰巧」)
表单场景请记住:先 Number(...) 或 parseInt(..., 10),再算。
你应能口头说出:为什么 "1"+2 不是 3。
步骤 2:三等号与宽松相等
0 == false; // true —— 宽松,会转换,业务里不推荐
0 === false; // false —— 严格:一个 number,一个 boolean
"5" === 5; // false
Number("5") === 5; // true
null == undefined; // true(宽松)
null === undefined; // false
业务判断请默认 === / !==。
不必背完整 == 对照表——少用就是最省事的策略。
步骤 3:|| 与 (默认值场景)
??
0 || 100; // 100 —— 0 被当成「假」
0 ?? 100; // 0 —— 0 是有效值,保留
"" || "无名"; // "无名"
"" ?? "无名"; // "" —— 空字符串不是 null/undefined
null ?? "无名"; // "无名"
undefined ?? "无名"; // "无名"
人话:要给缺省名,若 0、"" 也是合法业务值,优先 ??。
|| 适合「假值一律换成右边」的粗粒度场景。
步骤 4:短路与布尔上下文
// &&:左边为假则直接得左边;否则得右边
true && "继续"; // "继续"
false && "继续"; // false
// 假值常见清单(在 if 条件里当作「不成立」)
// false, 0, -0, 0n, "", null, undefined, NaN
const user = { name: "ada" };
// 常见写法:有 user 才读 name(现代更推荐可选链 user?.name)
const label = user && user.name;
console.log(label);
你应理解:if (value) 看的是「能否当成真」,不是「是否等于 true」。
步骤 5:小页面——年龄检查(显式转换)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>运算符</title>
</head>
<body>
<label>年龄 <input id="age" type="text" /></label>
<button type="button" id="check">检查</button>
<p id="out"></p>
<script>
document.getElementById("check").addEventListener("click", function () {
const raw = document.getElementById("age").value; // 字符串
const age = Number(raw.trim());
const out = document.getElementById("out");
// Number("") 是 0;Number("abc") 是 NaN —— 用 isFinite 拦住无效值
if (!Number.isFinite(age)) {
out.textContent = "请输入有效数字";
return;
}
// 三元适合短二选一;复杂分支请用 if
out.textContent = age >= 18 ? "成年" : "未成年";
});
</script>
</body>
</html>
试:输入 20 → 成年;输入 abc → 提示无效;输入空 → 也应提示无效(因为 Number("") 是 0 但空串业务上常算无效——这里 trim 后若为空,Number("")===0 仍可能通过;可再加 if (raw.trim() === "") 收紧,见步骤 6)。
步骤 6:收紧空输入,并练习模板字符串
document.getElementById("check").addEventListener("click", function () {
const raw = document.getElementById("age").value.trim();
const out = document.getElementById("out");
if (raw === "") {
out.textContent = "年龄不能为空";
return;
}
const age = Number(raw);
if (!Number.isFinite(age)) {
out.textContent = "请输入有效数字";
return;
}
const status = age >= 18 ? "成年" : "未成年";
out.textContent = `年龄 ${age}:${status}`;
});
你应看到:空输入被单独拦住;合法数字用模板字符串输出完整句子。
讲清楚要点
- 因为
+ 遇到字符串会拼接,所以做数学前先显式转数字。
- 因为
== 会偷偷转换类型,所以业务默认 ===,少背特例表。
- 因为假值包含
0 和 "",所以默认值场景要分清 || 与 ??。
- 因为
Number("abc") 得到 NaN,所以用 Number.isFinite / Number.isNaN 校验,而不是只看「转没转过」。
- 因为输入框值是字符串,所以比较大小、算总分前都要转换并处理空串。
- 因为短路会跳过右边表达式,所以右边若有副作用(改数据、请求),要清楚会不会执行。
你可能会懵的地方
-
NaN 是什么?
Not a Number。Number("abc") 得到 NaN。NaN === NaN 仍是 false,请用 Number.isNaN(x)。
-
!!value 是什么?
转成真正的布尔值。调试时可以,业务里写清楚条件通常更好读。
-
模板字符串和普通字符串?
反引号 `年龄是 ${age}` 可插入表达式;普通引号要用 + 拼接。
-
parseInt 和 Number 谁好?
Number("12px") 是 NaN;parseInt("12px", 10) 是 12。需要整段都是数字时用 Number + 校验更严;解析「前缀数字」才用 parseInt,并写上进制 10。
错法对照
| 错法 | 问题 | 正解 |
|---|
业务大量 == | 隐式坑难查 | 默认 === |
直接 "1"+2 当数学 | 变成字符串拼接 | 先 Number |
用 || 处理分数 0 | 0 被当成无 | 用 ?? |
只 Number(x) 不校验 | NaN 流入后续逻辑 | Number.isFinite |
| 空串当 0 通过校验 | 误判成年/未成年 | 先判断 trim() === "" |
自测三问
- 为什么输入框的值常常要先转换再比较大小?
=== 比 == 安全在哪里?
- 什么情况下优先
?? 而不是 ||?
小结一句话
先显式转换类型,再用 === 判断;默认值场景分清 || 与 ??,并用 Number.isFinite 拦住无效数字。
延伸