1. 循环练习题概述
循环是编程中最基础也最重要的概念之一,它允许我们重复执行某段代码,直到满足特定条件为止。无论是处理数组数据、批量操作文件,还是实现游戏逻辑,循环都扮演着关键角色。对于初学者来说,通过系统的循环练习题来掌握各种循环结构(如for、while、do-while等)的使用方法,是提升编程能力的必经之路。
在实际开发中,大约60%的代码都会包含某种形式的循环结构。常见的应用场景包括:数据遍历、批量处理、定时任务、游戏循环等。掌握循环不仅能提高代码效率,还能让程序逻辑更加清晰。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 循环基础与常见结构
2.1 for循环详解
for循环是最常用的循环结构,特别适合在已知循环次数的情况下使用。其基本语法如下:
javascript复制for (初始化表达式; 条件表达式; 更新表达式) {
// 循环体代码
}
一个典型的使用场景是遍历数组:
javascript复制const fruits = ['apple', 'banana', 'orange'];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
关键点说明:
- 初始化表达式:只在循环开始时执行一次,通常用于声明计数器变量
- 条件表达式:每次循环前都会检查,如果为true则继续循环
- 更新表达式:每次循环结束后执行,通常用于更新计数器
提示:在JavaScript中,使用let声明循环变量可以避免变量提升带来的问题,推荐始终使用let而非var。
2.2 while循环与do-while循环
while循环在不确定循环次数时特别有用,它会在每次迭代前检查条件:
javascript复制let count = 0;
while (count < 5) {
console.log(count);
count++;
}
do-while循环与while类似,但会先执行一次循环体再检查条件:
javascript复制let input;
do {
input = prompt("请输入yes退出:");
} while (input !== 'yes');
选择建议:
- 当至少需要执行一次循环体时,使用do-while
- 当可能一次都不需要执行时,使用while
- 当明确知道循环次数时,使用for
3. 循环控制语句
3.1 break与continue
break用于立即退出整个循环,而continue则是跳过当前迭代,继续下一次循环:
javascript复制// break示例
for (let i = 0; i < 10; i++) {
if (i === 5) break;
console.log(i); // 只输出0-4
}
// continue示例
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) continue;
console.log(i); // 只输出奇数
}
3.2 循环标签
对于嵌套循环,可以使用标签来指定break或continue的作用对象:
javascript复制outerLoop:
for (let i = 0; i < 3; i++) {
innerLoop:
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) break outerLoop;
console.log(`i=${i}, j=${j}`);
}
}
// 当i=1,j=1时直接退出外层循环
4. 循环性能优化
4.1 减少循环内部计算
将不变的计算移到循环外部可以显著提高性能:
javascript复制// 不推荐
for (let i = 0; i < array.length; i++) {
// ...
}
// 推荐
const length = array.length;
for (let i = 0; i < length; i++) {
// ...
}
4.2 循环展开
对于小型循环,手动展开可以减少循环开销:
javascript复制// 原始循环
for (let i = 0; i < 4; i++) {
process(i);
}
// 展开后
process(0);
process(1);
process(2);
process(3);
4.3 选择正确的循环方法
现代JavaScript提供了多种迭代方法,各有适用场景:
| 方法 | 特点 | 适用场景 |
|---|---|---|
| for | 最基础,性能最好 | 需要索引或精确控制 |
| for...of | 简洁,直接获取值 | 遍历可迭代对象 |
| forEach | 函数式风格 | 简单遍历,不需要中断 |
| while | 条件控制灵活 | 不确定循环次数时 |
5. 常见循环模式与实践
5.1 嵌套循环
嵌套循环常用于处理多维数据结构,如矩阵运算:
javascript复制const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(`matrix[${i}][${j}] = ${matrix[i][j]}`);
}
}
5.2 递归与循环
某些问题既可以用循环解决,也可以用递归。循环通常性能更好,而递归代码更简洁:
javascript复制// 循环实现阶乘
function factorialLoop(n) {
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// 递归实现阶乘
function factorialRecursive(n) {
return n <= 1 ? 1 : n * factorialRecursive(n - 1);
}
5.3 异步循环
处理异步操作时,需要注意循环的执行顺序:
javascript复制// 错误的异步循环
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 全部输出5
}
// 正确的异步循环
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 输出0-4
}
6. 循环练习题精选
6.1 基础练习题
- 打印1-100的所有偶数
javascript复制for (let i = 1; i <= 100; i++) {
if (i % 2 === 0) console.log(i);
}
- 计算1-100的和
javascript复制let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
console.log(sum); // 5050
6.2 中级练习题
- 找出100以内的所有质数
javascript复制outer: for (let i = 2; i < 100; i++) {
for (let j = 2; j < i; j++) {
if (i % j === 0) continue outer;
}
console.log(i);
}
- 打印九九乘法表
javascript复制for (let i = 1; i <= 9; i++) {
let line = '';
for (let j = 1; j <= i; j++) {
line += `${j}×${i}=${i*j}\t`;
}
console.log(line);
}
6.3 高级练习题
- 实现冒泡排序
javascript复制function bubbleSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}
- 生成斐波那契数列
javascript复制function fibonacci(n) {
const sequence = [0, 1];
for (let i = 2; i < n; i++) {
sequence[i] = sequence[i - 1] + sequence[i - 2];
}
return sequence;
}
7. 循环中的常见错误与调试
7.1 无限循环
忘记更新循环变量会导致无限循环:
javascript复制// 错误示例
let i = 0;
while (i < 10) {
console.log(i);
// 忘记i++
}
解决方法:
- 确保循环条件最终会变为false
- 使用调试工具设置断点检查变量变化
7.2 循环条件错误
错误的循环条件可能导致循环次数不符合预期:
javascript复制// 错误示例:想循环5次,实际循环6次
for (let i = 0; i <= 5; i++) {
console.log(i); // 输出0-5共6个数
}
7.3 循环变量作用域问题
使用var声明循环变量可能导致意外行为:
javascript复制for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出3个3
}
解决方法:
- 始终使用let声明循环变量
- 使用闭包保存变量值
8. 循环在现代JavaScript中的替代方案
8.1 数组迭代方法
ES5+提供了多种数组迭代方法,可以替代传统循环:
javascript复制const numbers = [1, 2, 3, 4, 5];
// forEach: 简单遍历
numbers.forEach(num => console.log(num));
// map: 转换数组
const squares = numbers.map(num => num * num);
// filter: 过滤数组
const evens = numbers.filter(num => num % 2 === 0);
// reduce: 累积计算
const sum = numbers.reduce((acc, num) => acc + num, 0);
8.2 生成器与迭代器
生成器函数可以创建自定义迭代逻辑:
javascript复制function* range(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
for (const num of range(1, 5)) {
console.log(num); // 输出1-5
}
8.3 for...of循环
for...of循环可以遍历任何可迭代对象:
javascript复制const str = "hello";
for (const char of str) {
console.log(char); // 输出h,e,l,l,o
}
9. 循环最佳实践
- 保持循环体简洁:如果循环体过长,考虑将部分逻辑提取为函数
- 避免在循环中创建函数:这会导致不必要的内存分配
- 使用描述性的变量名:i,j,k等单字母变量名在嵌套循环中容易混淆
- 注意循环终止条件:确保循环能够在预期条件下终止
- 考虑使用函数式方法:对于数组操作,map/filter/reduce等通常更清晰
10. 循环在实际项目中的应用案例
10.1 数据批量处理
javascript复制// 批量处理用户数据
async function batchProcessUsers(userIds) {
const BATCH_SIZE = 10;
for (let i = 0; i < userIds.length; i += BATCH_SIZE) {
const batch = userIds.slice(i, i + BATCH_SIZE);
await Promise.all(batch.map(processUser));
console.log(`已完成 ${Math.min(i + BATCH_SIZE, userIds.length)}/${userIds.length}`);
}
}
10.2 轮询检查状态
javascript复制// 轮询检查任务状态
async function waitForTaskCompletion(taskId, timeout = 30000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const status = await checkTaskStatus(taskId);
if (status === 'completed') return true;
if (status === 'failed') throw new Error('Task failed');
await new Promise(resolve => setTimeout(resolve, 1000));
}
throw new Error('Timeout waiting for task completion');
}
10.3 游戏主循环
javascript复制// 简单的游戏主循环
function gameLoop() {
let lastTime = 0;
function loop(timestamp) {
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
updateGameState(deltaTime);
renderGame();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
}
在实际编程中,我发现很多初学者容易陷入"循环恐惧症"——面对需要重复执行的任务时,要么复制粘贴大量相似代码,要么使用过于复杂的解决方案。其实,合理使用循环可以让代码更加简洁高效。特别是在处理集合数据时,熟练运用各种循环结构和控制语句,能够显著提高开发效率和代码质量。
