A03 运算符与类型转换

2026-10-31 17:271 阅读累计 不足 1 分钟约 10 分钟JavaScript
AI 摘要30 秒读完

讲解 JavaScript 运算符隐式类型转换规则,给出安全比较与真假值判断的实用写法。

  • 转换方向由运算符决定:+ 偏向字符串拼接,-、*、/ 偏向数值
  • 比较一律用 === 避免隐式转换带来的意外结果
  • 真假值判断需区分「有值」与「有内容」,空数组与空对象为真
  • 0 与空字符串是有效值时用 ?? 替代 || 做兜底
  • 对象参与运算会隐式调用 valueOf 与 toString
AI 生成 · 仅供参考

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 验证与讨论

  1. 在控制台执行 '5' + 1、'5' - 1、'5' * '2',对照图 3-1 解释结果。
  2. 执行表 3-1 中六类假值的 if 判断,确认全部走 else 分支。
  3. 把 options.limit || 10 改为 ??,观察分页参数从 10 变回 0。
  4. 构造 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

参考文献

[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

0/2000

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