Appearance
4. 会重复的小助手(循环)
知识点:循环
项目:画星星图案 + 九九乘法表
故事开场:1000 颗星星
美术节到了,老师要在教室后面的黑板上贴星星,说:"请你用程序帮我画星星!"
画星星嘛,太简单了,不就是输出一行行的 ★ 吗?你自信地敲起来:
ts
console.log("★")
console.log("★")
console.log("★")
// ……又来了,第 20 颗老师走过来看了看,说:"嗯,画得不错。我要 1000 颗。"
"1000 颗?"你看着屏幕里这堆 console.log,"那我要复制粘贴 1000 遍吗……"
老师又说:"对了,还要排成一个三角形,第一行 1 颗,第二行 2 颗, 第三行 3 颗,一共 10 行。明天早上能好吗?"
笨办法先行:复制粘贴的手
让我们感受一下,不复制粘贴,用"老老实实"的办法画 5 行三角形:
ts
console.log("★")
console.log("★★")
console.log("★★★")
console.log("★★★★")
console.log("★★★★★")能跑,对不对?5 行还行。可是:
- 想要 20 行?写 20 行代码。
- 想要 1000 行?写 1000 行代码。
- 想改成用"☆"画?把每一行都改一遍,漏改一行就露馅。
- 想画空心三角形?每一行都要重新算,手忙脚乱。
你发现了吗——问题不在"会不会画",而在"重复的劳动"。 计算机最擅长的就是重复劳动,而我们却在替它重复。
引出知识点:for 循环——给计算机下"重复指令"
循环(loop)就是"让一段代码反复执行"的指令。最常见的是 for 循环:
ts
for (let i = 0; i < 5; i++) {
console.log("★")
}这个循环做了什么?把它拆开看:
let i = 0:先拿一个计数器i,从 0 开始i < 5:每次开始前问"i还小于 5 吗?"——是,就继续做;不是,就停console.log("★"):循环要做的事(每次执行一遍)i++:做完一遍,i加 1
执行过程是这样的:
| 第几遍 | i 的值 | i < 5? | 做什么 | 最后 |
|---|---|---|---|---|
| 1 | 0 | ✅ | 输出 ★ | i = 1 |
| 2 | 1 | ✅ | 输出 ★ | i = 2 |
| 3 | 2 | ✅ | 输出 ★ | i = 3 |
| 4 | 3 | ✅ | 输出 ★ | i = 4 |
| 5 | 4 | ✅ | 输出 ★ | i = 5 |
| 6 | 5 | ❌ 停止 | 什么也不做 | — |
一共输出 5 颗星星。想画 1000 颗?把 i < 5 改成 i < 1000, 一行都不用多写。这就是计算机的"重复小助手"。
注意:i < 5 而不是 i <= 5。 因为从 0 开始数:0、1、2、3、4 正好 5 个数。 写循环时,这是最容易错的地方——少一次多一次,程序就错了。
动手实现:会画星星的小助手
先画一条直线(10 颗星星排成一排):
ts
let line = ""
for (let i = 0; i < 10; i++) {
line = line + "★" // 每循环一次,往线上加一颗星
}
console.log(line)输出:
★★★★★★★★★★再画三角形——三角形的秘密是:第 1 行 1 颗,第 2 行 2 颗,第 n 行 n 颗。 "第几行画几颗",这就是一个"外面的循环管行、里面的循环管颗"的问题:
ts
for (let row = 1; row <= 5; row++) {
let line = ""
for (let star = 0; star < row; star++) {
line = line + "★"
}
console.log(line)
}输出:
★
★★
★★★
★★★★
★★★★★循环套循环,叫"嵌套循环"。想想第 1 章我们见过它——那个 O(n²) 的"陷阱"! 外层跑 n 次,内层每次跑 n 次,一共 n × n 次。 画三角形也是:一共画了 1 + 2 + 3 + 4 + 5 = 15 颗星星,不多不少。
想画 10 行?把 row <= 5 改成 row <= 10,完事。1000 行?改一个数字,完事。 1000 颗星星和 1000 行三角形,对循环来说只是换了个数字。
跑起来:九九乘法表
最有名的"重复劳动"是九九乘法表。9 行,每行 9 个算式。 "第几行、第几列"——又是嵌套循环:
ts
for (let i = 1; i <= 9; i++) {
let line = ""
for (let j = 1; j <= i; j++) {
line = line + j + "×" + i + "=" + (j * i) + " "
}
console.log(line)
}输出(部分):
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
...
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81注意:这里外层 i 是"第几行",内层 j 从 1 到 i——因为第 i 行只写到 "i × i",三角形嘛。这个程序只有 9 行代码,却输出了 45 个算式。 这就是循环的意义:用一小段代码,驱动海量的重复劳动。
小挑战
- 倒三角:把三角形倒过来——第一行 5 颗,最后一行 1 颗 (提示:
row从大到小走,或者用5 - row + 1算颗数)。 - 空心三角:画一个"只有边框"的空心三角形(第一行 1 颗、最后一行满、 中间的行只在两端有星)。这个有点难,可以分两步:先画实心,再想 "什么时候该画星、什么时候该画空格"。
- 正方形:画一个 5×5 的实心正方形,再画一个 5×5 的空心正方形 (边框有星,中间空格)。
课后练习
第 1 题(动手题):星星计数器
修改画直线的程序,让它在画完星星后,再输出一共画了多少颗。 (提示:可以数一数 line.length,想一想:一颗星占几个字符?)
参考答案(点开查看)
ts
let line = ""
for (let i = 0; i < 10; i++) {
line = line + "★"
}
console.log(line)
console.log("一共画了 " + line.length + " 颗")输出 一共画了 10 颗。一颗星占一个字符,所以 line.length 就是星星的数量。
第 2 题(思考题):while 循环
for 循环还有个亲戚叫 while 循环:
ts
let i = 0
while (i < 5) {
console.log(i)
i++
}运行看看,它输出什么?和 for 循环相比,你觉得 while 适合什么场景?
参考答案(点开查看)
输出 0、1、2、3、4。
while 循环只有"条件":只要条件成立就一直做。适合"不知道要做多少次" 的情况,比如"直到用户输入'退出'才停止"。而 for 适合"知道要做多少次", 比如画 10 颗星星。
警告:如果忘记写 i++,i < 5 永远成立,程序会永远循环下去 (这叫死循环),只能按 Ctrl+C 强制停止。写循环前先问自己: "它真的会停下来吗?"
第 3 题(思考题):倒数
下面这个循环会输出什么?先在心里算,再运行验证。
ts
for (let i = 5; i > 0; i--) {
console.log(i)
}参考答案(点开查看)
输出 5、4、3、2、1。
i-- 是每次减 1,从 5 数到 1(i > 0 表示数到 0 就停,所以 0 不会输出)。 这和密信里"从最后一个字往前拼"是同一个思路——倒着遍历。
下一课预告:点名器、密信、画星星……三个程序里都藏着重复的代码。 老师说:"把它们装进魔法盒子,以后喊一声名字就能用。"——函数来了!