03运算符与流程控制
一个 JS 程序,本质就是数据 + 运算符 + 流程控制三件套。
运算符把数据组合成表达式(a + b、x > 10),
流程控制让程序按条件分支(if/switch)或循环(for/while)跑下去。
这一课把这两件武器一次讲完。
一、算术运算符与赋值运算符
最熟悉的一组:+ - * / % **。
** 是 ES7 引入的「幂」:2 ** 3 等于 8。
+ 是双面人——两边都是数字就相加,只要有一边是字符串就变成拼接。
所以 '5' + 3 得到字符串 '53',而 '5' - 3 因为减法没有「拼接」概念,字符串被自动转成数字,得到数字 2。
++ 和 -- 是自增 / 自减。前缀(++i)先加再用,
后缀(i++)先用再加——单独一行没差别,写进表达式里就翻车。
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
+ | 加 / 拼接 | 1 + 2 / '1' + 2 | 3 / '12' |
- | 减 | '5' - 3 | 2(自动转数字) |
* / / | 乘 / 除 | 6 / 4 | 1.5 |
% | 取余(取模) | 5 % 3 | 2 |
** | 幂(ES7) | 2 ** 10 | 1024 |
++ / -- | 自增 / 自减 | i++ / ++i | 看位置:先加还是后加 |
+= -= *= /= | 算术赋值 | x += 5 | x = x + 5 的简写 |
**= %= | 幂赋值 / 取余赋值 | x **= 2 | x = x ** 2 |
a 改成 '5' 字符串再看一遍—— + 变成拼接、 - 却仍是数字减法++i 先加再用,i++ 先用再加——写在表达式里差别巨大。
实战中能分开写就分开写,单独一行用谁都行,别埋进 arr[i++] 这种地方自找麻烦。二、比较与逻辑运算符
比较结果是 true / false。=== 严格相等(类型 + 值都相等),
== 会偷偷做类型转换,是JS 公认的坑——项目里只许用 ===。
逻辑三剑客:&&(与,全真才真)、||(或,一真就真)、!(非,取反)。
它们还有个隐藏技能——短路:能立刻判断结果时,后面的就不跑了。
ES2020 新加两个狠角色:?? 空值合并(只在 null/undefined 时兜底)、
?. 可选链(中间任意一环是 null/undefined 就直接返回 undefined,不报错)。
| 比较 | ==(松散) | ===(严格) |
|---|---|---|
| 0 与 '0' | 0 == '0' → true(字符串转数字) | 0 === '0' → false(类型不同) |
| null 与 undefined | null == undefined → true | null === undefined → false |
| '' 与 0 | '' == 0 → true | '' === 0 → false |
| [] 与 false | [] == false → true(绕) | [] === false → false |
data.bio 的 null 改成 {bio: 'hi'},可选链和 ?? 的输出会同时变?? 解决了 || 的老毛病:只要 0、空串、false 合法,就该用 ??,用 || 会被当成「没值」。三、三元运算符与短路求值
三元 条件 ? 值1 : 值2 是 if / else 的表达式版——
if/else 是语句、不返回值;三元是表达式、能塞进变量和模板字符串。
短路求值是逻辑运算符的副产品:a && b
从左往右找第一个 falsy,找到就返回它,全是真值就返回最后一个真值;
a || b 反过来找第一个真值。
实战中 || 常用来给「空值/0」兜底(但注意上面说的 ?? 更稳)。
|| 短路a ? b : c ? d : e ? f : g 立刻抽成 if/else。if/else 反过来也有规矩——
嵌套不超过 3 层,否则就是「金字塔噩梦」,先抽函数 / 早返回 / 卫语句。四、if / else if / else 条件分支
主力武器。if (条件) { ... } else if (条件) { ... } else { ... }
条件用括号包起来,执行的代码块用花括号包起来。
三条工程规矩:① 始终写花括号,哪怕只有一行——不加的话缩进出错就是 bug;
② else if 可以链多个,按顺序判定,第一个满足的就跑;③ 嵌套别超过 3 层,
否则就是「金字塔噩梦」,先抽函数 / 早返回 / 卫语句。
105 落到「无效」分支五、switch 多路分支
当一个变量要按多个固定值分支时,switch 比一长串 else if 更清晰。
经典结构:switch (x) → 多个 case → 每个 case 末尾必须 break,
最后用 default 兜底。
漏写 break 就会「穿透」——命中一个 case 后,下面所有 case 都会跑, 直到遇到第一个 break 或者 switch 结束。多数情况是 bug,但「多个 case 共享同一段代码」时是有意为之。
99 走 default 分支case 1 漏写 break,会顺路执行 case 2、case 3……
直到遇到第一个 break 或 switch 收尾。Lint 工具能帮你查,记得开。六、for 循环
最常用的循环:for (初始化; 条件; 更新) { ... }。
三段都可选:省略初始化就把变量声明写在上面;省略条件就是死循环;
省略更新就靠循环体内手动改。三段都写齐是标准范式。
循环内常用两个控制词:break(跳出整个循环,立刻停)
和 continue(跳过本次,进入下一轮)。
| 写法 | 适用场景 | 典型用法 |
|---|---|---|
标准 for | 已知循环次数 | for (let i=0; i<10; i++) |
省略段 for | 复杂初始化 / 步长在体内改 | for (;;) 死循环,靠 break 出 |
for...of | 遍历数组 / 可迭代对象的值 | for (const x of arr) |
for...in | 遍历对象的键(不推荐遍历数组) | for (const k in obj) |
七、while 与 do-while
不知道循环次数、只知「满足条件就继续」时,用 while (条件) { ... }——先判后做。
如果条件一开始就是假,循环体一次都不跑。
反过来想「无论怎样先做一次」,就用 do { ... } while (条件)——先做后判,
最典型的场景是输入验证:必须让用户至少输入一次,不合格就一直让他重新输入。
八、本章小结
- 算术
+ - * / % **,+会因字符串而变拼接,-不会——拼接/相减的区别常考。 - 比较只用
===和!==,避开==的隐式类型转换;逻辑&&/||/!都是短路求值。 - ES2020 新增
??(空值合并)和?.(可选链)——兜底字段首选??,比||更精准。 - 三元
条件 ? a : b是表达式版的 if/else,嵌套别超过 2 层。 - if/else 用卫语句把异常挡在最前面;switch 每个 case 必须 break,否则穿透。
- for 已知次数、while 条件循环、do-while 至少跑一次;
break跳出整层、continue跳过本轮。
for 输出 1~100 之间的素数,命中时用 console.log,非命中用 continue;
②用 switch 把月份(1~12)转季节(春 3-5 / 夏 6-8 / 秋 9-11 / 冬 12,1,2);
③用三元判断某年是否闰年((y % 4 === 0 && y % 100 !== 0) || y % 400 === 0);
④写一个 userInput ?? '匿名' 的兜底,验证 0 和 '' 都不会被替换。
每题写完用今天的 lab 套路挂按钮跑一遍。