javascript.info 循环改写实战:把 for 循环替换为 while 循环(5-replace-for-while 任务详解)

原创2026-09-30 16:12:331,451 阅读
文章标签:文档/教程前端

javascript.info 循环改写实战:把 for 循环替换为 while 循环(5-replace-for-while 任务详解)

本文围绕 Modern JavaScript Tutorial(javascript.info)中 1-js/02-first-steps/13-while-for/5-replace-for-while/task.md 这道经典练习展开:在不改变程序行为的前提下,把一段 for 循环改写为等价的 while 循环。读完本文,你将掌握两种循环语句在结构与执行顺序上的对应关系,学会"行为不变"的循环等价改写方法,并能通过逐步追踪验证改写结果的正确性。该任务位于教程"First Steps"章节的 Loops: while and for 主题之下,是检验初学者是否真正理解循环三要素(初始化、条件、步进)的标准练习题。

任务要求:改写循环而保持行为不变

原任务(importance: 5,属于高优先级核心练习)要求如下:

Rewrite the code changing the for loop to while without altering its behavior (the output should stay same).

即:把下面的 for 循环改写为 while 循环,不得改变程序行为,最终输出必须与原代码完全一致:

for (let i = 0; i < 3; i++) {
  alert( `number ${i}!` );
}

这段代码的运行效果是依次弹出三次对话框,内容分别为 number 0!、number 1!、number 2!。改写后的代码必须保持这三个输出值、输出顺序和输出次数不变。

先看懂 for 循环的三段式结构

要完成改写,首先要拆解 for 语句的三个组成部分。根据教程 Loops: while and for 中的说明,for 循环的标准语法为:

for (begin; condition; step) {
  // ... loop body ...
}

对应到本题:

部分 本题代码 作用
begin(初始化) let i = 0 进入循环时仅执行一次,声明并初始化计数器
condition(条件) i < 3 每次迭代前检查;为假则循环终止
body(循环体) alert(number ${i}!) 条件为真时反复执行
step(步进) i++ 每次循环体执行完毕后运行

for 循环的完整执行算法可以展开为:

Run begin
→ (if condition → run body and run step)
→ (if condition → run body and run step)
→ ...

代入本题,逐步展开就是:

// for (let i = 0; i < 3; i++) alert(`number ${i}!`)

// run begin
let i = 0
// if condition → run body and run step
if (i < 3) { alert(`number 0!`); i++ }   // i 变为 1
// if condition → run body and run step
if (i < 3) { alert(`number 1!`); i++ }   // i 变为 2
// if condition → run body and run step
if (i < 3) { alert(`number 2!`); i++ }   // i 变为 3
// ...finish, because now i == 3

可以看到,begin 只执行一次,之后是"条件检查 → 循环体 → 步进"的循环往复,直到 i 等于 3 时条件 i < 3 为假,循环结束。

改写为 while 循环:把三段式展开为显式语句

while 循环的语法只有"条件 + 循环体"两个要素:

while (condition) {
  // code
  // so-called "loop body"
}

改写思路很直接:把 for 的 begin 提前到循环外声明变量,把 condition 原样搬进 while 的条件位置,再把 step 移到循环体的末尾手动执行。官方参考答案位于 5-replace-for-while/solution.md:

let i = 0;
while (i < 3) {
  alert( `number ${i}!` );
  i++;
}

改写后的执行顺序与原 for 完全对应:

原 for 部分 while 改写位置
let i = 0(begin) 循环外的 let i = 0;
i < 3(condition) while (i < 3) 的条件
alert(...)(body) 循环体内的第一条语句
i++(step) 循环体末尾的 i++;

改写后的循环同样依次弹出 number 0!、number 1!、number 2!,满足"输出保持不变"的要求。

为什么这样改写是正确的:执行语义等价性验证

while 版本与 for 版本在语义上等价,关键在于步进的执行时机。for 循环中 i++ 在每次循环体执行完之后运行,while 版本把 i++ 放在循环体末尾,同样保证了:

  1. 首次进入循环时 i = 0,条件 0 < 3 为真,弹出 number 0!,随后 i++ 使 i = 1;
  2. 第二次检查 1 < 3 为真,弹出 number 1!,i++ 使 i = 2;
  3. 第三次检查 2 < 3 为真,弹出 number 2!,i++ 使 i = 3;
  4. 第四次检查 3 < 3 为假,循环终止。

把执行过程"展开"验证如下:

let i = 0;
// if (0 < 3) { alert(`number 0!`); i++ }
// if (1 < 3) { alert(`number 1!`); i++ }
// if (2 < 3) { alert(`number 2!`); i++ }
// if (3 < 3) → false, loop stops

如果漏写循环体末尾的 i++,循环条件永远为真,会形成无限循环——正如教程中特别提醒的:在浏览器环境中无限循环可以被用户强制停止,在服务端 JavaScript 中则只能终止进程。因此,把 step 从 for 头部搬到 while 循环体末尾,是改写中最容易遗漏、也最关键的一步。

改写中的细节要点

1. 计数器变量的作用域差异

for 中的 let i = 0 是"内联声明",变量 i 只在循环内部可见;循环结束后访问 i 会报错(ReferenceError)。而改写后的 while 版本把 i 声明在循环外部,循环结束后 i 依然存在,且值为 3。如果原 for 代码依赖内联变量的块级作用域(例如循环后有同名变量声明),改写时需要留意作用域变化;如果原代码使用的是循环外已存在的变量(如 for (i = 0; i < 3; i++)),则改写前后作用域一致。

2. for 与 while 的结构关系

教程指出,去掉 for 的 begin 和 step 之后,for (; i < 3;) { ... } 与 while (i < 3) { ... } 完全等价。这从侧面印证了:任何 for 循环都可以在不改变条件检查语义的前提下改写为 while,只需把三段内容拆开安置。反过来,while 循环也可写成省略 begin/step 的 for 形式。

3. 不要混淆 do..while

教程中的第三种循环 do..while 把条件检查放在循环体之后,保证循环体至少执行一次。本题要求"行为不变",因此必须使用先检查条件的 while 形式,而不能使用 do..while——后者在原 for 条件一开始就为假的情况下仍会执行一次循环体,行为不再等价。

4. 条件与递增的执行顺序

改写时注意保持"先检查、后递增"的顺序:while 的条件中不要直接写 i++(如 while (i++ < 3)),因为后缀自增会先返回旧值再递增,导致输出结果偏移。本题标准解法把递增放在循环体末尾,清晰还原了 for 中"body 之后执行 step"的顺序,这是保持输出一致最稳妥的写法。

相关练习题与延伸阅读

本节所属的 13-while-for 目录下还有一系列配套练习,可用来巩固循环语义:

  • 1-loop-last-value:分析 while (i) 配合 alert(i--) 时最后一次弹出的值(答案为 1),训练对真值转换与后缀自增的理解;
  • 2-which-value-while:对比 while (++i < 5) 与 while (i++ < 5) 输出序列的差异(分别输出 1~4 与 1~5),演示前后缀形式在条件表达式中的不同行为;
  • 3-which-value-for:证明 for 的 step 中 i++ 与 ++i 输出相同(均为 0~4),因为步进与条件检查分离,其返回值未被使用;
  • 4-for-even:用 for 配合取模运算符 % 输出 2 到 10 的偶数;
  • 6-repeat-until-correct 与 7-list-primes:进一步练习循环嵌套与终止条件设计。

小结

"把 for 改写为 while"表面上是一次机械的语法搬运,实际上考察的是对循环执行模型的理解:for 的 begin / condition / step / body 四要素如何按固定顺序反复执行。改写步骤可归纳为三条:

  1. 将 begin 提取为循环前的变量声明;
  2. 将 condition 原样放入 while 条件;
  3. 将 step 移入循环体末尾,且顺序必须在 body 之后。

遵循这三步即可保证输出不变,这也是本任务要求"without altering its behavior"的判定标准。读者可在浏览器控制台分别运行 task.md 与 solution.md 中的代码,逐一核对弹出的三次 alert 内容来验证等价性。

登录后查看全文
en.javascript.info