Web-Dev-For-Beginners 数组与循环实战作业:四道编程练习的完整解析与参考实现
【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners
数组(Arrays)与循环(Loops)是 JavaScript 数据处理的基石,本作业是 Web-Dev-For-Beginners 课程「JavaScript 基础」第 4 课(4-arrays-loops)的配套实战任务。通过完成数字模式生成、数组统计分析、字符串数组处理与对象数组过滤四道递进式练习,你将系统掌握for循环的自定义步长、for...of与forEach()等现代迭代语法,以及数组方法在真实数据处理中的应用。阅读完本文后,你将能独立完成全部练习与加分挑战,并理解如何在浏览器控制台、乃至本仓库的游戏与银行项目源码中运用这些能力。
作业背景:来自课程的数组与循环知识铺垫
本作业所依托的课程章节 2-js-basics/4-arrays-loops/README.md 提供了完成作业所需的全部前置知识:
- 数组创建与索引:使用方括号
[]创建数组,元素从索引 0 开始计数;可通过arr[index]读写元素,length属性动态反映数组大小。 - 常用数组方法:
push()/unshift()添加元素,pop()/shift()移除元素,indexOf()/includes()查找元素。 - 循环类型:
for循环(计数器驱动、适合已知迭代次数)、while循环(条件驱动、适合未知迭代次数)、for...of(ES6+,直接取元素值)、forEach()(函数式风格,回调接收元素与索引)。 - 组合应用:课程中给出了"单循环内同时完成求和、求最大、求最小"的统计模式,这正是练习 2 与练习 4 的直接技术来源。
课程为学习者提供了配套的课前/课后测验(Pre-Lecture Quiz 与 Post-Lecture Quiz),建议在动手写代码前先完成课程阅读,再进入下面的作业实战。
作业要求总览
作业要求完成以下四道练习,每道练习都建立在前一道的概念之上,并鼓励你尝试不同类型的循环与数组方法:
| 练习 | 主题 | 涉及核心语法 |
|---|---|---|
| 练习 1 | 数字模式生成器 | for循环自定义步长 |
| 练习 2 | 数组分析 | 函数封装 + 统计逻辑 |
| 练习 3 | 字符串数组处理 | for/for...of/forEach()对比 |
| 练习 4 | 数据过滤(进阶) | 对象数组 + 条件遍历 |
练习 1:数字模式生成器
任务:编写一个程序,列出 1 到 20 之间每隔 3 个数的数字,并在控制台输出。
要求:
- 使用带自定义递增步长的
for循环 - 以友好易读的格式显示数字
- 添加描述性注释解释你的逻辑
预期输出:
3, 6, 9, 12, 15, 18参考实现:
// 需求:列出 1 到 20 之间每隔 3 个数的数字 // 思路:从 3 开始,每次步进 3,直到超过 20 为止 const numbers = []; for (let i = 3; i <= 20; i += 3) { numbers.push(i); // 将每个符合条件的数字收集到数组中 } console.log(numbers.join(", ")); // 以逗号+空格拼接输出:3, 6, 9, 12, 15, 18提示:关键点在于修改 for 循环的迭代表达式(iteration expression)——把常见的
i++(步长 1)改为i += 3(步长 3)即可跳过不需要的数字。这与课程中提到的for(let i=0; i<arr.length; i+=2)遍历模式一脉相承。
变式思考:如果把起始值改为 1、步长保持 3,输出会变成1, 4, 7, 10, 13, 16, 19;把条件改为i <= 30则可以验证步长逻辑的边界行为。
练习 2:数组分析
任务:创建一个包含至少 8 个不同数字的数组,并编写函数对其进行分析。
要求:
- 创建名为
numbers的数组,至少包含 8 个值 - 编写
findMaximum()函数,返回数组中的最大值 - 编写
findMinimum()函数,返回数组中的最小值 - 编写
calculateSum()函数,返回所有数字的总和 - 测试每个函数并输出结果
加分挑战:编写一个函数找出数组中的第二大的数。
参考实现:
// 创建至少包含 8 个不同数字的数组 const numbers = [42, 17, 93, 8, 55, 31, 76, 24]; // 查找最大值:从第一个元素出发,逐一比较 function findMaximum(arr) { let max = arr[0]; // 先假设第一个元素最大 for (let i = 1; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; // 发现更大的值就更新 } } return max; } // 查找最小值:逻辑与最大值对称 function findMinimum(arr) { let min = arr[0]; for (let i = 1; i < arr.length; i++) { if (arr[i] < min) { min = arr[i]; } } return min; } // 求和:累加所有元素 function calculateSum(arr) { let sum = 0; for (let i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; } // 测试每个函数并输出结果 console.log(`最大值为: ${findMaximum(numbers)}`); // 93 console.log(`最小值为: ${findMinimum(numbers)}`); // 8 console.log(`总和为: ${calculateSum(numbers)}`); // 346 // —— 加分挑战:第二大值 —— function findSecondMaximum(arr) { // 先找出最大值,再在排除最大值的情况下找次大值 // 更稳健的做法:一次性遍历记录 top1 与 top2 let max = -Infinity; let secondMax = -Infinity; for (const num of arr) { if (num > max) { secondMax = max; // 原来的最大值降级为第二大 max = num; } else if (num > secondMax && num !== max) { secondMax = num; // 处理并列最大值之外的次大值 } } return secondMax; } console.log(`第二大的值为: ${findSecondMaximum(numbers)}`); // 76要点剖析:最大值/最小值函数的初始值通常取数组第一个元素(arr[0]),而不是 0 或任意猜测值——课程中的成绩统计示例正是这样初始化的。加分挑战的关键在于"降级"思想:当新元素超过当前最大值时,旧最大值自动成为第二大值。
练习 3:字符串数组处理
任务:创建一个包含你最喜欢的电影/书籍/歌曲的数组,练习不同类型的循环。
要求:
- 创建至少包含 5 个字符串值的数组
- 使用传统
for循环带编号显示元素(1. 元素名) - 使用
for...of循环以大写形式显示元素 - 使用
forEach()方法统计并显示所有元素的总字符数
示例输出:
Traditional for loop: 1. The Matrix 2. Inception 3. Interstellar For...of loop (uppercase): THE MATRIX INCEPTION INTERSTELLAR Character count: Total characters across all titles: 42参考实现:
// 至少 5 部喜欢的电影 const favorites = ["The Matrix", "Inception", "Interstellar", "The Shawshank Redemption", "Pulp Fiction"]; // 1. 传统 for 循环:带编号显示(i+1 将索引 0 起始转为人类可读的 1 起始) console.log("Traditional for loop:"); for (let i = 0; i < favorites.length; i++) { console.log(`${i + 1}. ${favorites[i]}`); } // 2. for...of 循环:直接取值,无需索引,用 toUpperCase() 转大写 console.log("\nFor...of loop (uppercase):"); for (const item of favorites) { console.log(item.toUpperCase()); } // 3. forEach 方法:累加每个字符串的长度 console.log("\nCharacter count:"); let totalCharacters = 0; favorites.forEach(item => { totalCharacters += item.length; }); console.log(`Total characters across all titles: ${totalCharacters}`);三种方式的取舍:传统for循环需要自己维护索引,适合需要序号或反向遍历的场景,但也存在 off-by-one(差一)错误的可能;for...of直接解出元素值、语法更简洁,但拿不到索引(如需序号需配合entries());forEach()函数式风格可同时拿到元素与索引((item, index)),但无法提前break跳出。作业要求你同时使用三种方式,正是为了体会它们各自的适用场景。
练习 4:数据过滤(进阶)
任务:编写程序处理表示学生的对象数组。
要求:
- 创建至少包含 5 个学生对象的数组,属性为:
name、age、grade - 使用循环找出年龄 18 岁及以上的学生
- 计算所有学生的平均成绩
- 创建只包含成绩高于 85 分的学生的新数组
示例结构:
const students = [ { name: "Alice", age: 17, grade: 92 }, { name: "Bob", age: 18, grade: 84 }, // 添加更多学生... ];参考实现:
const students = [ { name: "Alice", age: 17, grade: 92 }, { name: "Bob", age: 18, grade: 84 }, { name: "Charlie", age: 20, grade: 88 }, { name: "Diana", age: 19, grade: 78 }, { name: "Eve", age: 22, grade: 95 }, ]; // 1. 找出 18 岁及以上的学生(使用 for...of 遍历对象数组) const adults = []; for (const student of students) { if (student.age >= 18) { adults.push(student.name); } } console.log(`18 岁及以上的学生: ${adults.join(", ")}`); // Bob, Charlie, Diana, Eve // 2. 计算平均成绩(for 循环累加后除以总数) let totalGrade = 0; for (let i = 0; i < students.length; i++) { totalGrade += students[i].grade; } const averageGrade = totalGrade / students.length; console.log(`平均成绩: ${averageGrade.toFixed(2)}`); // 87.40 // 3. 创建成绩高于 85 分的学生新数组(使用 forEach 收集) const topStudents = []; students.forEach(student => { if (student.grade > 85) { topStudents.push(student); } }); console.log("成绩高于 85 分的学生:", topStudents.map(s => s.name).join(", ")); // Alice, Charlie, Eve进阶提示:练习 4 的"过滤"逻辑其实就是课程中提到的"Filtering (conditions)"处理模式的实现。完成练习后,可以进一步尝试把第 2、3 步改写成函数式写法——students.filter(s => s.grade > 85)、students.reduce((sum, s) => sum + s.grade, 0) / students.length——这正是课程结尾"Challenge"环节布置的现代数组方法重构任务,对比之后你会直观感受到代码可读性的提升。
测试你的代码
作业要求按以下步骤测试程序:
- 在浏览器控制台运行:打开浏览器开发者工具(F12),切换到 Console 标签,将代码粘贴后回车执行;
- 核对预期输出:将实际输出与题目给出的预期输出逐行比对;
- 更换数据集测试:修改数组内容、长度、数据类型(如全部为负数、包含小数),确认逻辑依然正确;
- 检查边界情况:空数组、单元素数组、重复最大值、全部相同值等极端输入下,函数是否仍能正确返回或至少不会抛错。
以练习 2 为例:若
numbers为空数组,arr[0]为undefined,比较结果会是NaN——可以就此思考如何为findMaximum增加空数组保护,这是真实项目中对入参健壮性的基本要求。
提交指南与评分标准
提交内容需包含:
- 每道练习的、注释良好的 JavaScript 代码;
- 程序运行结果的截图或文本输出;
- 一份简短说明,解释你为每项任务选择了哪种循环类型及原因。
评分标准(Rubric):
| 标准 | 优秀(3 分) | 合格(2 分) | 待改进(1 分) |
|---|---|---|---|
| 功能性 | 所有练习(含加分题)正确完成 | 所有必需练习运行正确 | 部分练习不完整或有错误 |
| 代码质量 | 干净、组织良好、变量命名有意义 | 代码可用但可以更整洁 | 代码混乱或难以理解 |
| 注释 | 全面注释,解释逻辑与决策 | 有基本注释 | 注释很少或没有 |
| 循环运用 | 恰当展示对不同循环类型的理解 | 循环使用正确但类型单一 | 循环使用错误或低效 |
| 测试 | 有多场景全面测试的证据 | 展示了基本测试 | 几乎没有测试证据 |
对照评分标准可以确认:要拿到"优秀",除了正确完成四道练习与加分挑战外,还需要在注释完整度、循环类型多样性和多场景测试证据上刻意打磨。
反思问题
完成练习后,建议思考以下问题以巩固理解:
- 哪种循环类型用起来最自然?为什么?(例如:
for...of因无需管理索引而直观,forEach因函数式风格而简洁) - 处理数组时你遇到了哪些挑战?(如索引越界、修改数组导致遍历异常、空数组边界等)
- 这些技能如何应用到真实的 Web 开发项目中?
- 如果要为性能优化你的代码,你会做哪些改动?(如避免在循环内重复计算
array.length、用filter/reduce替代多次遍历等)
仓库内循环与数组的真实应用佐证
本作业的能力点并非孤立练习——在仓库的项目源码中可以找到大量实际应用:
- 太空射击游戏6-space-game/solution/app.js 中,子弹、敌机与粒子系统都使用数组配合循环管理:例如第 346、357 行使用
for (let i = bullets.length - 1; i >= 0; i--)这种反向遍历模式在移除元素时避免索引错位;第 451、469、497 行用for (const e of enemies)等for...of遍历实体数组更新游戏状态;第 610 行使用list.forEach(item => {...})渲染列表。 - 银行应用7-bank-project/solution/app.js 中,第 209 行
for (const id of ids)遍历账户 ID 数组、第 344 行for (const tx of sorted)遍历排序后的事务数组——这正是练习 3、4 中"遍历对象/字符串数组"模式在真实业务(账户与交易流水)中的体现。
可以看到,无论游戏每帧的碰撞检测,还是银行应用的数据展示,"数组 + 循环"都是贯穿项目的基础设施。完成本作业后,你不只掌握了语法,更拥有了阅读和构建这类真实应用核心逻辑的能力。
延伸阅读与下一步
- 课程章节:2-js-basics/4-arrays-loops/README.md(含图示笔记与完整示例)
- 前置课程:2-js-basics/README.md(JavaScript 基础四课总览)
- 作业英文原版:2-js-basics/4-arrays-loops/assignment.md
完成作业后,你已为后续课程(如 3-terrarium 的 DOM 与闭包、4-typing-game 的打字游戏逻辑、6-space-game 的游戏循环)打下了坚实的数据处理基础——这些项目都深度依赖数组与循环,届时你会发现这里的每一项练习都有直接用武之地。
【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考