首页
/ 用 For 循环反向计数(Count Backwards With a For Loop)——freeCodeCamp 基础 JavaScript 阶梯课程详解

用 For 循环反向计数(Count Backwards With a For Loop)——freeCodeCamp 基础 JavaScript 阶梯课程详解

2026-09-07 20:36:54作者:郦嵘贵Just

导读

for 循环并不是只能从小到大正序递增,只要恰当设置初始化(initialization)、循环条件(condition)与最终表达式(final-expression)三要素,它同样可以从 10 一路倒数到 1。本文以 freeCodeCamp 开源课程仓库 basic-javascript 区块中的挑战“Count Backwards With a For Loop”(curriculum/challenges/english/blocks/basic-javascript/56105e7b514f539506016a5e.md)为主线,讲解递减 for 循环的原理、三要素如何协同改写、数组 push 的正确用法,并对照源码逐条拆解该挑战的自动化测试规则与参考解答,帮你彻底吃透“带步长的倒序遍历”。

挑战背景:正序步进只是 for 循环的默认姿势

在进入本挑战之前,课程已经通过两条前序挑战建立起了循环的基本心智模型:

本挑战正是“按 2 递增”思路的镜像版本:既然能按 2 递增,自然也能按 2 递减。从课程结构文件 basic-javascript.json 可以看到,本挑战紧跟在 “Iterate Odd Numbers With a For Loop” 之后、位于 “Iterate Through an Array with a For Loop” 之前,属于同一组“循环迭代”序列,其 challengeType: 1 表示这是一道经典的纯代码编写型挑战。

递减循环的三要素改写:一句三改

原挑战说明开宗明义:“A for loop can also count backwards, so long as we can define the right conditions.”(只要条件定义正确,for 循环也能倒数。)

for 循环的结构本质上由三个表达式决定:初始化、条件、最终表达式。要实现每轮递减 2,三个部分必须同时配合修改,缺一不可:

表达式段 正序示例(按 2 递增) 倒序示例(按 2 递减) 含义
initialization let i = 0 let i = 10 从终点值起步
condition i < 10 i > 0 只要大于 0 就继续
final-expression i += 2 i -= 2 每轮结束把 i 减 2

课程给出的标准演示代码如下:

const ourArray = [];

for (let i = 10; i > 0; i -= 2) {
  ourArray.push(i);
}

逐轮推演这段代码的执行过程:

  1. 初始化:i = 10
  2. 检查条件 10 > 0 成立,进入循环体,ourArray.push(10),随后执行 i -= 2i 变为 8;
  3. 检查 8 > 0 成立,push 8,i 变为 6;
  4. 依此类推,依次 push 6、4、2;
  5. i = 0 时,0 > 0 为假,循环终止。

最终 ourArray 的值为 [10, 8, 6, 4, 2]。注意数字 0 并没有被写入数组——这正是条件选用 > 0 而非 >= 0 的直接后果,理解这一点是把握“边界条件决定输出范围”的关键。

任务指令解析:构造降序奇数数组

原挑战的 --instructions-- 段落给出的任务非常简短而明确:

Push the odd numbers from 9 through 1 to myArray using a for loop.

把这句话拆成三条可验证的需求:

  1. 数字范围:9 到 1 之间的奇数,即 9, 7, 5, 3, 1
  2. 目标载体:写入已声明好的数组 myArray
  3. 手段约束:必须使用 for 循环(不得用 whileArray.fromfilter 等手段)。

值得注意的是,初始化时仓库已为你声明好容器:

// Setup
const myArray = [];

// Only change code below this line

myArray 使用 const 声明。这没问题——const 只禁止对变量本身重新赋值,并不禁止调用数组方法修改其内部内容,因此 myArray.push(...) 完全合法。这与前面课程“用 const 声明只读变量”以及“push 向数组末尾添加元素”两节的知识点形成呼应。

对照前驱挑战:只改两处即可完成任务

前驱挑战“Iterate Odd Numbers With a For Loop”已示范如何构建 [1, 3, 5, 7, 9]

const myArray = [];
for (let i = 1; i < 10; i += 2) {
  myArray.push(i);
}

本挑战要求的 [9, 7, 5, 3, 1] 与其互为镜像。要做的事情只有两件:

  • 把初始化值从 i = 1 改为 i = 9(从最大奇数起步);
  • 把最终表达式从 i += 2 改为 i -= 2(改为递减)。

而条件表达式可以保持不变,仍然使用 i > 0

for (let i = 9; i > 0; i -= 2) {

为什么 i > 0 依然正确?因为目标序列的最小值是 1,当 i = 1 时满足条件并 push 1,随后 i 变为 -1-1 > 0 为假,循环恰好终止——不会多写入任何多余元素。当然,写成 i >= 1 同样能通过,但 i > 0 是更贴合“奇数不小于 1”语义的常见写法。

自动化测试如何验证你的代码

freeCodeCamp 的每道挑战都带有 --hints-- 段落,这些断言会被课程测试运行器逐条执行。查看原文档(56105e7b514f539506016a5e.md),本挑战包含三条测试:

第 1 条:必须使用 for 循环

assert(/for\s*\([^)]+?\)/.test(__helpers.removeJSComments(code)));

该正则会在“移除所有 JS 注释之后”的提交代码里搜索 for ( 形式的语句,验证你是否真的用上了 for 循环。调用 removeJSComments 的目的,是防止有人把 for 字样藏在注释中投机取巧。

第 2 条:必须使用数组方法 push

assert(__helpers.removeJSComments(code).match(/myArray.push/));

检测提交代码中是否包含 myArray.push 调用,确保元素是通过 push 追加进数组的。

第 3 条:结果值必须精确匹配

assert.deepEqual(myArray, [9, 7, 5, 3, 1]);

deepEqual 会做深度相等比较:不仅数组长度要一致,每个下标位置的元素也必须逐一相等、顺序分毫不差。因此任何“顺序颠倒”“漏项”“多一项”的输出都会在这一条被拦截。

参考解答与自检清单

原文档的 --solutions-- 段给出标准解答:

const myArray = [];
for (let i = 9; i > 0; i -= 2) {
  myArray.push(i);
}

写完代码后,建议用下述清单自检:

  • [ ] 循环体使用的变量确实是 i(与初始化声明一致,避免把 i 误写成 iI 等笔误);
  • [ ] 初始化值是 9,最终表达式是 i -= 2
  • [ ] push 的目标是 myArray,且 push 语句位于循环体花括号 { } 内部;
  • [ ] 循环条件保证在 push 完 1 后不会再继续(不会出现负数入数组);
  • [ ] 未在 // Only change code below this line 上方改动初始化代码。

也可以自行在浏览器控制台或 Node REPL 中逐步验证:在循环体内临时加上 console.log(i),观察控制台应依次打印 9 7 5 3 1,随后打印结束。

易错点与延伸思考

递减循环常见三类错误

  1. 条件方向写反for (let i = 9; i < 0; i -= 2) 由于初始化时 9 < 0 即为假,循环体一次都不会执行,myArray 保持为空。
  2. 最终表达式写成递增i += 2i = 9 组合会得到 9 < 0 恒为假之外的另一个极端——i 越来越大、永不停机(具体取决于条件写法),轻则死循环,重则让测试环境超时。
  3. 错用 const 声明计数器for (const i = 9; ...) 会在第二轮尝试给 i 重新赋值时报错,因为循环变量每轮都需更新,必须使用 let

递减循环的真实用途

倒序遍历在工程中非常常见,例如:从数组末尾往前查找满足条件的元素、在正向遍历删除元素会引发索引错位时改用反向遍历、实现倒计时逻辑等。掌握“三要素联动修改”的技巧后,你可以在任何维度控制遍历方向与步长——甚至用 i -= 1 做步长为 1 的倒数、用 i /= 2 做指数衰减。

本挑战随后将进入“Iterate Through an Array with a For Loop”(basic-javascript.json),届时你会把这些循环技巧应用到真实数组的逐个元素访问上,本挑战打下的“参数联动”基本功将直接复用。

关联文件速查

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525