JavaScript while 和 do…while 循环

简介

循环用于重复执行一段代码。JavaScript 提供了多种循环方式,本文重点介绍 whiledo...while 两种循环语句。

如果你知道循环的具体次数,通常使用 for 循环更合适;如果循环次数不确定,则 whiledo...while 更合适。


while 循环

基本语法

while (condition) {
  // 只要 condition 为真,就重复执行这里的代码
}

执行流程:

  1. 判断 condition 条件
  2. 如果为真,执行循环体
  3. 执行完后回到步骤 1
  4. 如果为假,跳出循环

示例

// 从 1 数到 5
let i = 1;
while (i <= 5) {
  console.log(i);
  i++;  // 别忘了更新循环变量,否则会无限循环!
}
// 输出:1 2 3 4 5

注意事项

必须更新循环变量(或改变条件状态):

// 错误的写法:无限循环!
let i = 1;
while (i <= 5) {
  console.log(i);
  // 忘记 i++ 了!
}

// 正确的写法
let i = 1;
while (i <= 5) {
  console.log(i);
  i++;  // 更新循环变量
}

循环变量可以在循环体内定义,但要小心作用域:

// 常见写法:循环变量在外部定义
let count = 0;
while (count < 3) {
  console.log('count:', count);
  count++;
}

// 使用场景:读取未知长度的数据时
let data = [1, 2, 3, 4, 5];
let index = 0;
while (index < data.length) {
  console.log(data[index]);
  index++;
}

常见使用场景

场景 1:处理不确定次数的操作

// 模拟不断接收消息,直到收到 "exit"
let messages = ['hello', 'world', 'exit'];
let i = 0;

while (i < messages.length && messages[i] !== 'exit') {
  console.log('收到消息:', messages[i]);
  i++;
}
// 输出:收到消息: hello  收到消息: world

场景 2:等待某个条件满足

// 模拟等待某个异步操作完成(简化示例)
let isReady = false;
let attempts = 0;

while (!isReady && attempts < 3) {
  console.log('等待中... 尝试次数:', attempts);
  attempts++;
  // 模拟某个条件达成
  if (attempts === 2) {
    isReady = true;
  }
}
console.log('准备就绪!');

场景 3:输入验证(配合 prompt 等)

// 浏览器环境示例(Node.js 中需其他方式获取输入)
// let age;
// while (isNaN(age) || age < 0 || age > 150) {
//   age = parseInt(prompt('请输入有效年龄 (0-150):'));
// }
// console.log('你的年龄是:', age);

do…while 循环

基本语法

do {
  // 至少执行一次,然后判断 condition
} while (condition);

执行流程:

  1. 先执行一次循环体
  2. 判断 condition 条件
  3. 如果为真,回到步骤 1
  4. 如果为假,跳出循环

与 while 的关键区别

while:先判断,后执行(可能一次都不执行)

let x = 10;
while (x < 5) {
  console.log('这句话不会执行');
  x++;
}
console.log('x =', x); // x = 10(循环体没执行)

do…while:先执行,后判断(至少执行一次)

let y = 10;
do {
  console.log('这句话会执行一次');
  y++;
} while (y < 5);
console.log('y =', y); // y = 11(循环体执行了一次)

示例

// 至少执行一次的示例
let count = 0;
do {
  console.log('当前 count:', count);
  count++;
} while (count < 3);
// 输出:
// 当前 count: 0
// 当前 count: 1
// 当前 count: 2

适用场景

场景 1:菜单选择(至少显示一次)

// 模拟简单的菜单选择(浏览器环境)
// let choice;
// do {
//   choice = prompt('选择操作: 1-新建 2-打开 3-保存 0-退出');
//   switch (choice) {
//     case '1': console.log('新建文件'); break;
//     case '2': console.log('打开文件'); break;
//     case '3': console.log('保存文件'); break;
//     case '0': console.log('退出'); break;
//     default: console.log('无效选择');
//   }
// } while (choice !== '0');

场景 2:至少要尝试一次的操作

// 模拟重试机制
let maxRetries = 3;
let attempt = 0;
let success = false;

do {
  attempt++;
  console.log(`尝试第 ${attempt} 次...`);
  // 模拟某次成功
  if (attempt === 2) {
    success = true;
    console.log('成功!');
  }
} while (!success && attempt < maxRetries);

if (!success) {
  console.log('达到最大重试次数,失败');
}

场景 3:读取用户输入直到有效(至少询问一次)

// let input;
// do {
//   input = prompt('请输入非空的用户名:');
// } while (!input || input.trim() === '');
// console.log('用户名:', input);

break 和 continue

两种循环都支持 breakcontinue 来控制循环流程。

break:跳出整个循环

// while 中使用 break
let i = 1;
while (i <= 10) {
  if (i === 5) {
    break;  // 当 i 等于 5 时,跳出整个循环
  }
  console.log(i);
  i++;
}
// 输出:1 2 3 4

// do...while 中使用 break
let j = 1;
do {
  if (j === 3) {
    break;
  }
  console.log(j);
  j++;
} while (j <= 5);
// 输出:1 2

continue:跳过本次循环,进入下一次

// while 中使用 continue
let i = 0;
while (i < 5) {
  i++;
  if (i === 3) {
    continue;  // 跳过 i === 3 时的后续代码
  }
  console.log(i);
}
// 输出:1 2 4 5(没有 3)

// do...while 中使用 continue
let j = 0;
do {
  j++;
  if (j === 2 || j === 4) {
    continue;
  }
  console.log(j);
} while (j < 5);
// 输出:1 3 5(没有 2 和 4)

注意事项

// continue 在 while 循环中要小心更新变量
let i = 0;
while (i < 5) {
  if (i === 2) {
    i++;        // 必须更新,否则会无限循环
    continue;
  }
  console.log(i);
  i++;
}
// 输出:0 1 3 4

无限循环

如何避免无限循环

// 危险:无限循环!
// while (true) {
//   console.log('永不停止');
// }

// 危险:条件永远为真
// let x = 5;
// while (x > 0) {
//   console.log(x);
//   // 忘记 x-- 了!
// }

// 安全:确保循环条件最终会变为假
let count = 0;
while (count < 100) {
  console.log(count);
  count++;
}

故意使用无限循环的场景

有时无限循环是有用的,配合 break 控制退出时机。

// 游戏主循环
// while (true) {
//   // 处理输入
//   // 更新游戏状态
//   // 渲染画面
//
//   if (gameOver) {
//     break;  // 游戏结束,退出循环
//   }
// }

// 服务器监听
// while (true) {
//   let request = await getNextRequest();
//   if (request === null) break;
//   handleRequest(request);
// }

while vs for:如何选择

特性 while for
循环次数 不确定次数时更合适 确定次数时更合适
语法简洁性 循环变量需在外部定义 变量初始化、条件、更新都在一行
可读性 适合条件复杂的场景 适合简单的计数循环
循环变量作用域 在外部可见 可在循环内定义(let)

对比示例

// 用 while:循环次数不确定
let num = Math.random() * 100;
let guesses = 0;
while (num > 10) {
  num = Math.random() * 100;
  guesses++;
}
console.log(`用了 ${guesses} 次才得到 <= 10 的数`);

// 用 for:循环次数确定
for (let i = 0; i < 5; i++) {
  console.log(i);
}
// 更简洁,变量 i 的作用域在循环内

相互转换

// while 循环
let i = 0;
while (i < 5) {
  console.log(i);
  i++;
}

// 等价的 for 循环
for (let i = 0; i < 5; i++) {
  console.log(i);
}

综合示例

示例 1:猜数字游戏

function guessNumber() {
  let target = Math.floor(Math.random() * 100) + 1;  // 1-100 的随机数
  let attempts = 0;
  let guess;

  console.log('我想了一个 1-100 之间的数字,来猜猜看!');

  do {
    // guess = parseInt(prompt('请输入你的猜测 (1-100):'));
    // 这里用随机模拟,实际环境用 prompt
    guess = Math.floor(Math.random() * 100) + 1;
    attempts++;

    if (guess < target) {
      console.log('太小了!');
    } else if (guess > target) {
      console.log('太大了!');
    } else {
      console.log(`恭喜!你用了 ${attempts} 次猜中了数字 ${target}!`);
    }
  } while (guess !== target && attempts < 10);  // 限制最多 10 次

  if (guess !== target) {
    console.log(`游戏结束!正确答案是 ${target}`);
  }
}

// guessNumber(); // 调用函数开始游戏

示例 2:数组处理(寻找满足条件的元素)

function findFirstNegative(arr) {
  let i = 0;
  let result = null;

  while (i < arr.length) {
    if (arr[i] < 0) {
      result = { value: arr[i], index: i };
      break;  // 找到第一个就退出
    }
    i++;
  }

  return result;
}

console.log(findFirstNegative([1, 3, 5, -2, 4])); // { value: -2, index: 3 }
console.log(findFirstNegative([1, 2, 3]));        // null

示例 3:数字反转

function reverseNumber(num) {
  let original = num;
  let reversed = 0;

  while (num > 0) {
    let digit = num % 10;       // 取最后一位
    reversed = reversed * 10 + digit;  // 拼接到结果
    num = Math.floor(num / 10); // 去掉最后一位
  }

  return reversed;
}

console.log(reverseNumber(12345)); // 54321
console.log(reverseNumber(100));  // 1(注意:前导零会被去掉)

示例 4:密码验证(至少尝试一次)

function verifyPassword(correctPassword) {
  let input;
  let attempts = 0;
  const maxAttempts = 3;

  do {
    // input = prompt('请输入密码:');
    // 模拟输入
    input = attempts === 1 ? correctPassword : 'wrong';
    attempts++;

    if (input === correctPassword) {
      console.log('密码正确!');
      return true;
    } else if (attempts < maxAttempts) {
      console.log(`密码错误,还有 ${maxAttempts - attempts} 次机会`);
    }
  } while (attempts < maxAttempts);

  console.log('超过最大尝试次数,账户已锁定!');
  return false;
}

// verifyPassword('123456');

总结:while vs do…while

特性 while do…while
执行顺序 先判断,后执行 先执行,后判断
最少执行次数 0 次(条件为假时不执行) 1 次(至少执行一次)
适用场景 循环次数不确定,可能不执行 循环次数不确定,至少要执行一次
分号 不需要 需要(while (condition); 末尾分号)

选择建议

  • 循环体可能不执行 → 使用 while
  • 循环体至少要执行一次 → 使用 do...while
  • 循环次数已知 → 考虑使用 for 更简洁
  • 循环次数不确定 → 使用 whiledo...while