A03 运算符与类型转换
讲解 JavaScript 运算符隐式类型转换规则,给出安全比较与真假值判断的实用写法。
- 转换方向由运算符决定:+ 偏向字符串拼接,-、*、/ 偏向数值
- 比较一律用 === 避免隐式转换带来的意外结果
- 真假值判断需区分「有值」与「有内容」,空数组与空对象为真
- 0 与空字符串是有效值时用 ?? 替代 || 做兜底
- 对象参与运算会隐式调用 valueOf 与 toString
A03 运算符与类型转换
摘要:JavaScript 在运算前会把操作数转换为统一类型,
+偏向字符串拼接,-、*、/偏向数值,==会做类型转换而===不会。绝大多数隐式转换问题集中在+、==、真假值判断三处。本文给出转换规则表、安全比较写法与四条替代方案。
关键词:运算符,隐式转换,严格相等,真假值,空值合并
所属:frontend/js / A-入门 | 上一篇:A02-变量与数据类型 | 下一篇:A04-条件分支与循环
1 引言
"5" + 1 得到 "51","5" - 1 得到 4,[] == false 得到 true。这些结果来自规范定义的转换规则,不是浏览器怪癖。规则本身可预测,但对阅读代码的人是负担。
本文给出三条实用规则:+ 与其它算术运算符方向不同、比较一律用 ===、真假值判断区分「有值」与「有内容」。范围见表 1-1。
| 项 | 本文覆盖 | 本文不覆盖 |
|---|---|---|
| 算术 | + - * / % **,一元运算符 |
位运算与移位 |
| 比较 | ===、==、大小比较 |
对象自定义比较(C02) |
| 转换 | Number、String、Boolean、?? |
日期与本地化格式化 |
2 预备知识
| 项 | 要求 | 核对方式 |
|---|---|---|
| 环境 | 浏览器控制台 | 能逐行执行表达式 |
| 前置 | A02 | 能区分原始类型与对象 |
| 文件 | js-practice/operators.js |
编码 UTF-8 |
3 原理与实现
3.1 转换发生在运算之前
二元运算先按运算符要求把两侧转成同一类型,如图 3-1 所示。
flowchart TD
A["操作数 a op b"] --> B{运算符}
B -->|"+"| C["任一侧为字符串 → 双方转字符串拼接"]
B -->|"+, - 一元"| D["ToNumber"]
B -->|"- * / % **"| D
C --> E["结果"]
D --> F["任一侧为 NaN → 结果 NaN"]
F --> E
G["对象参与运算"] --> H["先调用 valueOf,再调用 toString"]
H --> B
图 3-1 运算符决定转换方向,对象先转原始值
图上可见:转换方向由运算符决定,与操作数书写顺序无关;对象参与运算时会隐式调用
valueOf与toString。
3.2 安全写法
// js-practice/operators.js;运行环境:Chrome 130+
// 1 数值输入统一显式转换
const raw = ' 12px ';
const n = Number.parseInt(raw, 10); // 12
const bad = Number(raw); // NaN,整串必须合法
console.log(n, Number.isNaN(bad)); // 12 true
// 2 字符串拼接前显式转字符串
const count = 3;
console.log('共 ' + count + ' 条'); // 共 3 条
console.log(`共 ${count} 条`); // 推荐:模板字符串
// 3 比较一律严格相等
console.log(0 == ''); // true,隐式转换
console.log(0 === ''); // false
console.log([1] == 1); // true
console.log([1] === 1); // false
// 4 有值判断与有内容判断分开
const options = { limit: 0 };
console.log(options.limit || 10); // 10,0 被当成假值
console.log(options.limit ?? 10); // 0,只对 null/undefined 兜底
// 5 逻辑赋值与三元
let retries = null;
retries ??= 3;
console.log(retries); // 3
const label = retries > 2 ? '重试' : '直连';
console.log(label); // 重试
真假值规则见表 3-1,只有六类值在条件判断中为假。
| 分类 | 为假的值 | 说明 |
|---|---|---|
| 空值 | undefined、null、NaN |
无值或非法数值 |
| 数字零 | 0、-0、0n |
注意 0 是有效业务值 |
| 空字符串 | "" |
空格字符串为真 |
| 其余 | 对象、数组、函数、非空字符串、非零数字 | [] 与 {} 均为真 |
空值合并与逻辑或的差异见表 3-2。
| 写法 | 兜底条件 | 适用场景 |
|---|---|---|
a || b |
a 为任意假值 |
空字符串、0 视为缺失时 |
a ?? b |
a 为 null/undefined |
0 与 "" 是有效值时 |
a?.b |
仅当 a 为空值返回 undefined |
深层取值 |
4 验证与讨论
- 在控制台执行
'5' + 1、'5' - 1、'5' * '2',对照图 3-1 解释结果。 - 执行表 3-1 中六类假值的
if判断,确认全部走else分支。 - 把
options.limit || 10改为??,观察分页参数从 10 变回 0。 - 构造
const o = { valueOf: () => 42 },执行o + 1,确认结果为43。
| 检查项 | 预期结果 | 说明 |
|---|---|---|
| 加号拼接 | "51" |
任一侧为字符串即拼接 |
| 减号转数值 | 4 |
算术运算统一转数字 |
| 严格比较 | 0 === "" 为 false |
不转换类型 |
| 空值兜底 | 0 ?? 10 为 0 |
只对空值生效 |
| 对象转原始值 | o + 1 为 43 |
调用 valueOf |
讨论与局限。 位运算会先把操作数转成 32 位整数,超过范围时截断,不适合大数计算。另,Number.parseInt 会忽略尾部非法字符,Number 不会,校验用户输入时应先用 Number 再回退。
5 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 金额相加变成字符串拼接 | 一侧来自 input.value |
先 Number(...) 再运算 |
NaN 传播到全部计算 |
某一步转换失败 | 入口处校验,用 Number.isNaN 判断 |
| 分页传 0 却变成默认值 | 用了 || |
改用 ?? |
if (arr) 判断失效 |
空数组为真 | 用 arr.length > 0 |
0.1 + 0.2 !== 0.3 |
二进制浮点误差 | 金额用整数分单位存储 |
6 结论
| 序号 | 结论 | 依据 |
|---|---|---|
| 1 | 转换方向由运算符决定 | 图 3-1 |
| 2 | 比较一律用 === |
3.2 节 |
| 3 | 0 与空字符串有效时用 ?? 而非 || |
表 3-2 |
| 4 | 空数组与空对象在条件中为真 | 表 3-1 |
- 上一篇:A02-变量与数据类型
- 下一篇:A04-条件分支与循环
- 返回:A00-总结 | 科目 README
参考文献
[1] MDN Web Docs · 表达式与运算符,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_operators(访问于 2026-10-31)
[2] ECMA-262 · 7.2 Type Conversion,https://tc39.es/ecma262/#sec-type-conversion(访问于 2026-10-31)

评论 0
还没有评论,快来抢沙发吧~