Skip to content

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?做什么最后
10输出 ★i = 1
21输出 ★i = 2
32输出 ★i = 3
43输出 ★i = 4
54输出 ★i = 5
65❌ 停止什么也不做

一共输出 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 个算式。 这就是循环的意义:用一小段代码,驱动海量的重复劳动。


小挑战

  1. 倒三角:把三角形倒过来——第一行 5 颗,最后一行 1 颗 (提示:row 从大到小走,或者用 5 - row + 1 算颗数)。
  2. 空心三角:画一个"只有边框"的空心三角形(第一行 1 颗、最后一行满、 中间的行只在两端有星)。这个有点难,可以分两步:先画实心,再想 "什么时候该画星、什么时候该画空格"。
  3. 正方形:画一个 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 不会输出)。 这和密信里"从最后一个字往前拼"是同一个思路——倒着遍历。


下一课预告:点名器、密信、画星星……三个程序里都藏着重复的代码。 老师说:"把它们装进魔法盒子,以后喊一声名字就能用。"——函数来了!