上一篇:05 条件判断:=== 才是正道(if/else · 逻辑连接词 · 三元 · switch)
上篇练习参考答案
练习 1(手动模拟):“1” == 1、“1” === 1、null == undefined、null === undefined、0 == false、0 === false 各得什么? 
"1" == 1 得 true "1" === 1 得 false null == undefined 得 true null === undefined 得 false 0 == false 得 true 0 === false 得 false 六题就是 == 隐式转换的全部把戏——规则没人背得完,所以军规只有一条:写 ===。
练习 2(预测再验证):const x = 0; 之后执行 if (x = 5) { console.log(“A”); } else { console.log(“B”); } 输出什么?x 最后的值变成了多少?为什么?
会报错:Uncaught TypeError: Assignment to constant variable,因为 x = 5 是把 5 赋予 x 了,而 const 定义的变量不可变!
而当把 const x = 0 改可以重新赋值的 let x = 0 后,输出 "A",且 x 最终变成 5,相当于: x = 5; // 先把 5 赋值给 x if (5) { // 相当于用 if 直接判断 5 ,而 5 在 JavaScript 的布尔判断里是 truthy ,达成 if 条件所以输出A 这就是单个等号的阴险之处:不报错,只换逻辑。 
练习 3(改造要点):给判定器加"旷考"分支——score === -1 表示旷考,等级判为"旷考"、结论判为"需联系教务";注意 else if 的顺序该插在哪(提示:-1 < 60,放最前面判断); score === -1 必须放在最前面——不然 -1 会先命中 score < 60 误判成不及格 正确骨架:
const score = –1;
if (score === –1) {
grade = "旷考";
} else if (score >= 90) {
grade = "优秀";
} else if (score >= 75) {
grade = "良好";
} else if (score >= 60) {
grade = "及格";
} else {
grade = "不及格";
}
console.log(grade);
console.log(`结论:${score === –1 ? "需联系教务" : (score >= 60 ? "平安落地" : "补考")}`);
结论行用三元的话需要嵌套一层:score === -1 ? "需联系教务" : (score >= 60 ? "平安落地" : "补考")——嵌套三元能写但难读,超过两层就该用 if。
练习 4(疫苗揭晓):现在判定器只能判一个学生。全班 8 个人、8 个分数,难道把判定区复制 8 遍?电脑最擅长的事就是重复——06 篇的循环三行代码判 800 人。动手前先在纸上想:判定区哪些行是"每个学生都要跑一遍"的,哪些行是"全班只需跑一遍"的?(这个思考就是 07 篇函数化的预热。) 每人都要跑的:等级判定链(同样的规则重复用); 全班只跑一次的:报告标题、分隔线。 想清楚"哪些重复、哪些不重复",是写循环前最重要的思考——本篇整篇都在练这件事。
一、场景引入:手写的极限

把前五篇的三个"手写之痛"摆在一起看:
- 02 篇:星星树手写 5 行,每行数着空格敲;
- 03 篇练习:你发现了规律(第 n 层 = repeat(15-n) 空格 + repeat(2n-1) 星),但规律只能装在脑子里,手上还是一行行抄;
- 05 篇:判定器写好了,可它只认识一个学生。
痛感是同一个:该重复的事,只能靠手复制。循环就是解药——把"重复的规律"交给机器执行。今天学完,星星树改一个数字就能长一百层,报表一秒算完一百年。
二、本篇目标
三、知识点讲解
3.1 for 循环:三段式
for (let i = 1; i <= 5; i++) {
console.log(`第 ${i} 遍`);
}

圆括号里三个格子,用分号隔开,各管一件事:
| 起点 | let i = 1 | 计数器从几开始 |
| 终点 | i <= 5 | 到几停(每圈开始前检查,不满足就散场) |
| 步子 | i++ | 每圈结束加一(i++ 是 i = i + 1 的简写) |
执行顺序:起点 → 检查终点 → 跑大括号 → 迈步子 → 再检查终点……终点不满足,循环结束。i 就是 03 篇说的"标签",不过是循环自动管理的专用标签——在循环里数数,永远用它,别自己发明。顺带一提:计数器习惯命名为 i、j、k——不是语法规定,是全世界的约定俗成;你这么写,别人读你的代码就一眼能认出"这是个计数器"。
现在把 03 篇的星星树规律装进来——三行代码,七层树:
for (let n = 1; n <= 7; n++) {
console.log(" ".repeat(15 – n) + "*".repeat(2 * n – 1));
}

规律进循环,层数随便改:n <= 7 改成 n <= 30,三十层。这就是 03 篇预告的"手写到自动"的跃迁——你负责发现规律,循环负责重复到吐。
3.2 while:条件说了算的循环
for 的三段式适合"次数已知"。另一类循环次数未知、条件说了算:倒计时到 0、剩余次数减到 0、温度降到目标值……用 while:
let fuel = 3;
while (fuel > 0) {
console.log(`燃料剩余 ${fuel} 格,继续飞行`);
fuel—; // 千万别忘:条件里动的变量,循环里必须真的动
}
console.log("燃料耗尽,弹射!");

结构更简单:while (条件) { 循环体 }——条件真就转一圈再查,假就出门。分工口诀:次数已知用 for,条件说了算用 while。
死循环警告:while 的条件永远真,页面当场卡死(转圈、点不动)。头号成因就是忘写 fuel–——条件里的变量永远不变,条件永远成立。真卡住了别慌:关掉这个标签页重开就行。写 while 的自检动作只有一条:进循环前问自己"条件里的变量,循环体里谁在改它?"
3.3 break 与 continue:两张逃生券
先认识一个小工具:%(取余)——10 % 3 得 1(10 除以 3 余 1)。它最经典的用途是判断倍数:i % 3 === 0 表示"i 是 3 的倍数"。
两张逃生券(都写在循环体里):
- break:提前退场。 循环里一撞见它,整个循环立刻终止;
- continue:跳过这一圈。 撞见它,本轮剩下的代码不跑,直接迈步子进下一圈。
for (let i = 1; i <= 20; i++) {
if (i === 13) {
break; // 撞到 13,整个循环散场
}
if (i % 3 === 0) {
continue; // 3 的倍数跳过不打印
}
console.log(i); // 输出 1 2 4 5 7 8 10 11(到 12 的下一圈撞 13 停)
}

一句话分工:break 是"不干了",continue 是"这个不干,下一个继续"。查找"第一个满足条件的"用 break;过滤"不要某类"用 continue。
3.4 累加器:统计的看家模式
编程里一半的循环在干同一件事:把一堆数加起来。固定套路三步:
let total = 0; // ① 循环外先备一个"账本"(初始 0)
for (let i = 1; i <= 100; i++) {
if (i % 2 === 0) { // ② 圈内判断:这笔要不要记
total += i; // ③ 记账:total = total + i 的简写
}
}
console.log(total); // 1~100 的偶数和

三条纪律:账本必须在循环外用 let 声明(循环内声明 = 每圈换新本子,白记);累加用 += 简写;初始值是 0 不是别的。这个模式以后会反复穿上马甲出场——累计工资、统计销量、汇总账单,骨架全是它。
顺带认识它的孪生兄弟:累乘器——+= 换 *=、初始值换 1,就能算阶乘(5! = 5×4×3×2×1)。初始值是这套模式最容易翻车的细节:加法账本从 0 起(0 加谁都不变),乘法账本从 1 起(1 乘谁都不变)——乘法账本要是初始化成 0,乘到天荒地老结果还是 0。一句话记住:空账本加法给 0,空账本乘法给 1。
四、完整实战:批量生成器三件套
新建 生成器三件套.html,三段实战一次到位:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>批量生成器三件套</title>
</head>
<body>
<h2>批量生成器三件套</h2>
<p>生成结果在控制台——按 F12 查看。</p>
<script>
// ===== 第一件:任意层星星树(改 TREE_FLOORS 就改层数)=====
const TREE_FLOORS = 7;
console.log(`生成 ${TREE_FLOORS} 层星星树(for 循环 3 行代码)`);
for (let n = 1; n <= TREE_FLOORS; n++) {
console.log(" ".repeat(TREE_FLOORS + 8 – n) + "*".repeat(2 * n – 1));
}
// ===== 第二件:1~100 汇总报表(累加器 × 3)=====
let sumAll = 0; // 全部之和
let sumEven = 0; // 偶数之和
let sumThree = 0; // 3 的倍数之和
for (let i = 1; i <= 100; i++) {
sumAll += i;
if (i % 2 === 0) {
sumEven += i;
}
if (i % 3 === 0) {
sumThree += i;
}
}
console.log("=".repeat(40));
console.log(" 1 ~ 100 汇总报表");
console.log("=".repeat(40));
console.log(`全部数字之和:${sumAll}`);
console.log(`偶数之和:${sumEven}`);
console.log(`3 的倍数之和:${sumThree}`);
console.log("=".repeat(40));
// ===== 第三件:倒计时发射(while 条件驱动)=====
let count = 5;
while (count > 0) {
console.log(`倒计时:${count}`);
count—;
}
console.log("发射!");
// ===== 附赠:break 演示——找到第一个 7 的倍数就收工 =====
for (let i = 100; i <= 200; i++) {
if (i % 7 === 0) {
console.log(`100 之后第一个 7 的倍数是 ${i},收工(break)`);
break;
}
}
</script>
</body>
</html>
看结构:第一件是"规律重复"(for 的主场),第三件是"条件驱动"(while 的主场),第二件是累加器三连——三种循环形态各自站在最擅长的岗位上。
五、运行效果

生成 7 层星星树(for 循环 3 行代码)
*
***
*****
*******
*********
***********
*************
========================================
1 ~ 100 汇总报表
========================================
全部数字之和:5050
偶数之和:2550
3 的倍数之和:1683
========================================
倒计时:5
倒计时:4
倒计时:3
倒计时:2
倒计时:1
发射!
100 之后第一个 7 的倍数是 105,收工(break)
六、常见报错与排查
现象 1:页面卡死、转圈点不动(死循环)
原因:while 条件永远为真——最常见是忘了在循环体里改条件变量(忘写 count–)。 解决:关掉卡死的标签页重开;然后检查 while:条件里动到的变量,循环体里谁在改它? 没人改就是死循环。
现象 2:星星树只出了 6 层(少一圈)
原因:终点写成了 n < TREE_FLOORS——n 等于 7 时条件不成立,第 7 圈没跑。< 和 <= 差的那一圈,是"差一错误"(off-by-one)的经典现场。 解决:想清楚"最后一层要不要"——要就 <=,不要就 <。循环边界永远在心里数一遍首尾两个值:n=1 时跑不跑?n=7 时跑不跑?
报错 3:SyntaxError: Unexpected token(for 那行)
原因:for 三段之间的分号写成了逗号,或漏了一段(for (let i = 1, i <= 5, i++) 不合法)。 解决:三个格子两根分号,背下来:for (起点; 终点; 步子)。
排查心法:卡死查步子,少一圈查 <,语法错查分号。循环三大坑一句话打包。
七、练习作业
下一篇预告:《07 函数:把代码打包复用》——参数、返回值、箭头函数,以及"什么时候该抽函数"的判断手感。


