跟着 MDN 学JavaScript day_16:技能测试——循环实战演练

发布时间:2026/6/9 9:29:08

跟着 MDN 学JavaScript day_16:技能测试——循环实战演练 引言理论知识的学习为我们搭建了理解循环的框架但真正的编程能力需要在解决具体问题的过程中锤炼。今天我们进入循环的技能测试环节通过三道精心设计的题目来检验你是否真正掌握了for、while和do...while循环的用法以及break和continue语句在循环控制中的作用。这些题目不仅考察循环本身还会涉及 DOM 操作、数组遍历、对象属性访问以及条件判断等综合知识。三道题目各自要求使用不同的循环类型这种设计迫使我们必须灵活切换思维模式而不是机械地套用一种结构。让我们逐一拆解这些题目在实战中巩固循环的运用能力。一、实用的 DOM 操作在开始解题之前我们需要了解一个贯穿三道题目的基础技能那就是使用 JavaScript动态创建和操作 HTML 元素。虽然本课程尚未系统地讲解 DOM 操作但这三道题目都要求我们通过 JavaScript 来创建新元素、设置其内容并将其添加到页面中。三个核心 APIAPI作用示例document.createElement()创建一个新的 HTML 元素document.createElement(li)element.textContent设置或获取元素的文本内容listItem.textContent tomatoesparent.appendChild()将子元素追加到父元素中list.appendChild(listItem)createElement()的参数是标签名称的字符串ul创建无序列表、li创建列表项、p创建段落创建出来的元素需要通过appendChild()方法添加到页面中某个已有的父元素里才能最终显示在屏幕上元素内部的文本内容通过textContent属性来设置。这三个 API 组合起来就构成了用 JavaScript 动态生成页面内容的最小工具集。在第一题中我们需要创建多个列表项并将它们逐个追加到列表中在第二题中我们需要将搜索结果写入一个段落并追加到展示区域第三题同样需要将找到的质数结果写入段落。理解这个基本的 DOM 操作流程是顺利解答三道题目的前提。二、循环 1遍历数组并生成列表第一道题目为我们设定了这样一个场景有一个名为myArray的数组里面存储了五种食材的字符串包括西红柿、鹰嘴豆、洋葱、大米和黑豆。同时起始代码已经帮我们创建好了一个空的无序列表元素list我们可以在 JavaScript 中直接使用它。2.1 任务目标编写一个循环遍历myArray中的每一个元素完成以下操作为每个元素创建一个列表项li元素将当前数组元素的值赋给列表项的文本内容将这个列表项追加到list无序列表中。最终list会被起始代码自动添加到页面的展示区域。constmyArray[tomatoes,chick peas,onions,rice,black beans];constlistdocument.createElement(ul);// Add your code here// Dont edit the code below here!constsectiondocument.querySelector(section);section.appendChild(list);2.2 解题思路与代码实现这道题考察的是最基本的for循环配合数组遍历的模式for(leti0;imyArray.length;i){constlistItemdocument.createElement(li);listItem.textContentmyArray[i];list.appendChild(listItem);}执行流程迭代imyArray[i]操作第1次0tomatoes创建litomatoes/li并追加到ul第2次1chick peas创建lichick peas/li并追加第3次2onions创建lionions/li并追加第4次3rice创建lirice/li并追加第5次4black beans创建liblack beans/li并追加终止5—5 5为false循环结束DOM 操作三步走createElement(li) → textContent myArray[i] → list.appendChild(listItem) 创建元素 设置文本内容 追加到父元素这道题虽然简单但它完美地展示了循环在动态生成页面内容时的核心作用——我们不需要手动编写五个li标签只需要一个循环就能处理任意长度的数组。如果将来食材列表扩展到五十种代码依然只有这几行完全不需要改动。这就是循环所带来的可扩展性的力量。三、循环 2搜索电话簿并提前退出第二道题目将我们带入了一个更贴近实际应用的场景。我们有一个电话簿数组phonebook其中每个元素都是一个对象包含name和number两个属性。题目要求使用一种在上一道任务中没有使用过的循环类型即不能用普通for循环。3.1 任务目标在电话簿中搜索给定的名字Mustafa如果找到了匹配的联系人将该联系人的名字和电话号码输出到段落para中使用break语句立即退出循环不再继续搜索后续条目。constnameMustafa;constparadocument.createElement(p);constphonebook[{name:Chris,number:1549},{name:Li Kang,number:9634},{name:Anne,number:9065},{name:Francesca,number:3001},{name:Mustafa,number:6888},{name:Tina,number:4312},{name:Bert,number:7780},{name:Jada,number:2282},]// Add your code here// Dont edit the code below here!constsectiondocument.querySelector(section);section.appendChild(para);3.2 解题思路与代码实现既然不能用for循环自然的选择就是while循环leti0;while(iphonebook.length){if(phonebook[i].namename){para.textContent${phonebook[i].name}s number is${phonebook[i].number}.;break;}i;}while循环三要素的分布要素在代码中的位置具体写法初始化器循环之前let i 0退出条件while括号内i phonebook.length最终表达式循环体末尾i执行流程i0 → Chris ≠ Mustafa → i → 继续 i1 → Li Kang ≠ Mustafa → i → 继续 i2 → Anne ≠ Mustafa → i → 继续 i3 → Francesca≠ Mustafa → i → 继续 i4 → Mustafa Mustafa → 输出结果 → break → 循环终止 i5 → (永远不会到达已经被 break 终止)3.3 关键细节break 的价值如果没有break语句即使已经找到了 Mustafa循环仍然会继续遍历后面的 Tina、Bert 和 Jada做无意义的检查。对于只有 8 条记录的电话簿来说这无关紧要但如果电话簿有 10000 条记录而目标恰好在前 10 条break就能节省 99.9% 的循环时间。这道题的核心价值在于让我们体会while循环与break语句配合使用的典型场景处理一个需要提前退出的线性查找任务。while循环将计数器的管理逻辑分散开来在某些场景下这种分散反而让搜索逻辑更加清晰。四、循环 3倒序筛选质数第三道题目在逻辑上最为复杂它融合了倒序遍历、条件过滤以及continue语句的运用。题目要求使用一种在前两个任务中没有使用过的循环类型排除了for和while。4.1 任务目标变量i初始值为500被明确指定为迭代器变量para是一个已创建好的段落元素用于输出结果函数isPrime(num)用于判断传入的数字是否为质数是质数返回true不是则返回false任务要求使用循环倒序从大到小遍历从 2 到 500 的所有数字对于每个数字调用isPrime()进行检测如果不是质数使用continue跳过当前迭代不执行输出如果是质数则将该数字追加到para.textContent中用分隔符隔开。质数大于 1 且只能被 1 和自身整除的自然数1 不算质数。leti500;constparadocument.createElement(p);functionisPrime(num){for(leti2;inum;i){if(num%i0){returnfalse;}}returntrue;}// Add your code here// Dont edit the code below here!constsectiondocument.querySelector(section);section.appendChild(para);4.2 解题思路与代码实现既然for和while都已经被前两道题使用过了剩下的选择就是do...while循环do{if(!isPrime(i)){i--;continue;}para.textContent${i},;i--;}while(i2);do...while循环三要素的分布要素在代码中的位置具体写法初始化器循环之前let i 500题目已提供退出条件while括号内循环末尾i 2最终表达式循环体末尾i--出现在两处执行流程图解i500 → 进入循环体 ├─ isPrime(500)? → false → i-- (i499) → continue → 回到 while 检查 ├─ i499 → isPrime(499)? → true → 追加 499, → i-- (i498) ├─ i498 → isPrime(498)? → false → i-- (i497) → continue ├─ i497 → isPrime(497)? → ... └─ ... 重复直到 i1 → 退出条件 i 2 为 false → 循环终止4.3 ⚠️ 关键陷阱continue 与计数器的顺序这道题最易出错的地方在于continue语句的使用位置。看下面的对比// ❌ 错误会导致无限循环do{if(!isPrime(i)){continue;// 直接跳到 while 检查i 没有递减}para.textContent${i},;i--;}while(i2);// ✅ 正确在 continue 之前先递减 ido{if(!isPrime(i)){i--;// 先递减计数器continue;// 再跳过本次迭代}para.textContent${i},;i--;}while(i2);原理continue会跳过循环体内剩余的代码直接跳转到while条件检查。如果在continue之前没有更新ii将永远不变退出条件永远无法满足从而导致无限循环。这是一个非常常见的陷阱务必牢记在循环中使用continue时必须确保迭代器在continue之前已经更新。五、三道题目综合对比对比维度循环 1循环 2循环 3循环类型forwhiledo...while遍历方向正序0 → n正序0 → n倒序500 → 2循环控制自然结束break提前退出continue跳过迭代数据结构字符串数组对象数组数值 函数判断DOM 操作创建多个li写入单个p拼接写入p核心考点基本遍历 动态生成线性查找 提前退出条件过滤 倒序递减六、常见错误与避坑指南6.1 忘记初始化计数器// ❌ 错误while(iphonebook.length){...}// i 未定义// ✅ 正确leti0;while(iphonebook.length){...}6.2 忘记在循环体中更新计数器// ❌ 错误无限循环leti0;while(i5){console.log(i);// 忘记 i}// ✅ 正确leti0;while(i5){console.log(i);i;}6.3 退出条件写反// ❌ 错误循环一次都不执行do{para.textContenti;i--;}while(i2);// i 初始为 500条件立假// ✅ 正确do{para.textContenti;i--;}while(i2);总结完成这三道技能测试题我们经历了一次从基础到进阶的循环实战训练。题目循环类型核心技能关键收获生成食材列表for遍历数组 DOM 动态创建循环的可扩展性——代码行数与数据规模解耦搜索电话簿while对象属性访问 break线性查找中提前退出的性能优化模式筛选质数do...while倒序遍历 continuecontinue前必须更新计数器避免无限循环三道题目覆盖了三种不同的循环结构每一种都在特定的场景下展现出其独特的价值。更重要的是它们共同揭示了循环编程中必须时刻留意的核心原则清晰的初始化——计数器从哪开始正确的退出条件——什么时候停止边界情况对吗可靠的迭代器更新——每次迭代是否都向退出条件靠近当你能够根据问题的特性自如地选择最合适的循环类型并正确处理提前退出break与跳过迭代continue的逻辑时你就真正掌握了 JavaScript 中循环的精髓。还在为 JavaScript 代码写得像“意大利面条”、逻辑混乱难以维护而头秃收藏本文持续跟进后续将系统分享 JS 高效语法糖、浏览器兼容与 Polyfill 实战、手写核心源码解析、常见坑点避雷指南从基础语法到进阶逻辑一站式打通助你快速提升前端开发硬实力

相关新闻