Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
01-【JavaScript-Day 1】从零开始:全面了解 JavaScript 是什么、为什么学以及它与 Java 的区别
02-【JavaScript-Day 2】开启 JS 之旅:从浏览器控制台到 <script>
标签的 Hello World 实践
03-【JavaScript-Day 3】掌握JS语法规则:语句、分号、注释与大小写敏感详解
04-【JavaScript-Day 4】var
完全指南:掌握变量声明、作用域及提升
05-【JavaScript-Day 5】告别 var
陷阱:深入理解 let
和 const
的妙用
06-【JavaScript-Day 6】从零到精通:JavaScript 原始类型 String, Number, Boolean, Null, Undefined, Symbol, BigInt 详解
07-【JavaScript-Day 7】全面解析 Number 与 String:JS 数据核心操作指南
08-【JavaScript-Day 8】告别混淆:一文彻底搞懂 JavaScript 的 Boolean、null 和 undefined
09-【JavaScript-Day 9】从基础到进阶:掌握 JavaScript 核心运算符之算术与赋值篇
10-【JavaScript-Day 10】掌握代码决策核心:详解比较、逻辑与三元运算符
11-【JavaScript-Day 11】避坑指南!深入理解JavaScript隐式和显式类型转换
12-【JavaScript-Day 12】掌握程序流程:深入解析 if…else 条件语句
13-【JavaScript-Day 13】告别冗长if-else:精通switch语句,让代码清爽高效!
14-【JavaScript-Day 14】玩转 for
循环:从基础语法到遍历数组实战
15-【JavaScript-Day 15】深入解析 while 与 do…while 循环:满足条件的重复执行
文章目录
前言
在上一篇【JavaScript-Day 14】中,我们学习了 for
循环,它非常适合在迭代次数已知或可预测的情况下使用。然而,在编程中,我们经常会遇到一些场景:需要在满足特定条件时才重复执行某段代码,而这个重复的次数在循环开始之前是未知的。这时,while
循环和 do...while
循环就派上了用场。本文将带你深入理解这两种循环结构的原理、用法、区别以及它们在实际开发中的应用,并探讨如何使用 break
和 continue
控制循环流程。
一、while 循环:当条件为真时重复
while
循环是最基本的循环结构之一,它的核心思想是:只要指定的条件为真 (truthy),就会不断地重复执行循环体内的代码块。
1.1 什么是 while 循环?
想象一下 while
循环就像一个警惕的门卫。门卫面前有一条规则(循环条件),每次有人想通过(执行循环体代码)时,门卫都会检查这条规则。如果规则得到满足(条件为真),门卫就放行;如果不满足(条件为假),则禁止通行,循环结束。
这种循环机制非常适合那些我们不知道具体要循环多少次,但知道循环应该在什么条件下持续或停止的场景。
1.2 while 循环的语法结构
while
循环的语法非常简洁:
while (condition) {
// 当 condition 为 true 时执行的代码块
// 也称为循环体
// 重要:循环体内部通常需要有代码来改变 condition,
// 否则可能导致无限循环
}
condition
:这是一个布尔表达式,在每次循环迭代开始前都会被求值。- 如果
condition
的值为true
(或可以被转换为true
的值,即 truthy 值),则执行循环体内的代码。 - 如果
condition
的值为false
(或可以被转换为false
的值,即 falsy 值),则循环终止,程序将执行while
循环之后的代码。
- 如果
我们可以用流程图来更直观地表示 while
循环的逻辑:
1.3 while 循环的执行流程
while
循环的执行流程可以概括为以下几步:
- 条件检查:首先,计算圆括号
()
内的condition
表达式的值。 - 执行或跳过:
- 如果条件为
true
,则执行花括号{}
内的循环体代码。执行完毕后,返回步骤 1,再次进行条件检查。 - 如果条件为
false
,则跳过循环体代码,整个while
循环结束,程序继续执行循环结构之后的代码。
- 如果条件为
这个过程会一直重复,直到条件变为 false
。
1.4 while 循环代码示例
下面通过几个例子来理解 while
循环的应用。
1.4.1 基础计数示例
这是一个经典的计数器示例,从 0 打印到 4:
let count = 0; // 初始化计数器
while (count < 5) { // 设置循环条件
console.log("当前 count 值是: " + count); // 循环体:打印当前 count 值
count++; // 关键:更新条件变量,使其能最终变为 false
}
console.log("循环结束,最终 count 值是: " + count); // 输出:5
代码解析:
- 初始化
count
为 0。 - 第一次检查:
0 < 5
为true
,打印 “当前 count 值是: 0”,count
变为 1。 - 第二次检查:
1 < 5
为true
,打印 “当前 count 值是: 1”,count
变为 2。 - …
- 第五次检查:
4 < 5
为true
,打印 “当前 count 值是: 4”,count
变为 5。 - 第六次检查:
5 < 5
为false
,循环终止。 - 最后打印 “循环结束,最终 count 值是: 5”。
1.4.2 处理用户输入(直到有效)
假设我们需要用户输入一个介于 1 到 10 之间的数字:
// 假设我们有一个获取用户输入的函数 promptUser (在浏览器中可以是 prompt)
// 这里我们用一个模拟函数
function promptUser(message) {
// 在 Node.js 环境下,可以使用 readline 模块,或简单模拟
const readlineSync = require('readline-sync'); // 需要先 npm install readline-sync
const answer = readlineSync.question(message + ' ');
return answer;
}
let userInput = "";
let number = 0;
while (number < 1 || number > 10 || isNaN(number)) { // 条件:数字小于1 或 大于10 或 不是一个数字
userInput = promptUser("请输入一个 1 到 10 之间的数字:");
number = parseInt(userInput); // 尝试将输入转换为数字
if (isNaN(number)) {
console.log("输入无效,请输入一个数字!");
} else if (number < 1 || number > 10) {
console.log("数字必须在 1 到 10 之间!");
}
}
console.log("你输入的有效数字是: " + number);
代码解析:
- 循环会一直执行,直到用户输入的
number
是一个有效的数字,并且这个数字在 1 到 10 的范围内。 isNaN(number)
用于检查转换后的结果是否为NaN
(Not a Number)。- 这个例子展示了
while
循环在处理不确定次数的用户交互或数据验证时的实用性。
1.5 使用 while 循环的注意事项
(1) 避免无限循环 (Infinite Loops)
最常见的 while
循环错误是忘记在循环体内更新导致条件最终变为 false
的变量。如果条件永远为 true
,循环将永远执行下去,这就是所谓的“无限循环”或“死循环”,它会导致程序卡死或浏览器崩溃。
// 错误的示例:无限循环
let i = 0;
while (i < 5) {
console.log("这是一个无限循环!");
// 错误:没有更新 i 的值,i 永远是 0,条件 i < 5 永远为 true
}
如何避免: 始终确保循环体内部有逻辑可以影响循环条件,使其在某个时刻能够变为 false
。
(2) 条件变量的初始化
确保在循环开始前正确初始化用于条件的变量。
二、do…while 循环:先执行再判断
do...while
循环与 while
循环非常相似,但有一个关键区别:do...while
循环至少会执行一次循环体内的代码,然后再检查条件。
2.1 什么是 do…while 循环?
可以把 do...while
循环想象成一个“先试后买”的策略。你会先试用产品一次(执行循环体),然后再决定是否继续使用(检查条件)。无论条件最初是 true
还是 false
,循环体至少会执行一次。
2.2 do…while 循环的语法结构
do...while
循环的语法如下:
do {
// 至少会执行一次的代码块(循环体)
// 同样需要有代码来改变 condition
} while (condition); // 注意:这里有一个分号 (;)
do { ... }
:花括号内是循环体代码。while (condition);
:在循环体执行之后,检查condition
。如果为true
,则重复执行循环体;如果为false
,则循环终止。- 重要:
do...while
语句的while (condition)
之后必须有一个分号;
。这是与while
语句的一个显著语法区别。
流程图如下:
可以看到,“执行循环体代码” 在 “条件判断” 之前。
2.3 do…while 循环的执行流程
- 执行循环体:首先,无条件地执行
do
后面的花括号{}
内的循环体代码。 - 条件检查:然后,计算
while
后圆括号()
内的condition
表达式的值。 - 重复或跳出:
- 如果条件为
true
,则返回步骤 1,再次执行循环体。 - 如果条件为
false
,则循环终止,程序继续执行do...while
结构之后的代码。
- 如果条件为
2.4 do…while 循环代码示例
do...while
最适合那些无论如何都需要至少执行一次操作的场景。
2.4.1 至少执行一次的场景:菜单选择
假设我们想向用户展示一个菜单,并至少让他们选择一次,直到他们选择退出选项。
// 模拟 promptUser 函数
function promptUserChoice(message) {
const readlineSync = require('readline-sync');
const choice = readlineSync.question(message + '\n');
return choice;
}
let userChoice;
do {
console.log("\n--- 菜单 ---");
console.log("1. 开始游戏");
console.log("2. 查看帮助");
console.log("3. 设置选项");
console.log("4. 退出");
userChoice = promptUserChoice("请输入你的选择 (1-4):");
switch (userChoice) {
case '1':
console.log("游戏开始!");
break;
case '2':
console.log("这是帮助信息...");
break;
case '3':
console.log("设置已打开。");
break;
case '4':
console.log("感谢使用,正在退出...");
break;
default:
console.log("无效选择,请重新输入。");
}
} while (userChoice !== '4'); // 当用户选择的不是 '4' (退出) 时,继续循环
console.log("程序已退出。");
代码解析:
- 无论
userChoice
最初是什么,菜单都会先显示一次,并提示用户输入。 - 只有当用户输入
'4'
时,userChoice !== '4'
这个条件才会变为false
,循环才会结束。 - 如果用户输入其他无效字符,循环会因为条件为
true
而继续。
2.5 do…while 与 while 的核心区别
总结一下 while
和 do...while
的主要区别:
特性 | while 循环 | do...while 循环 |
---|---|---|
条件检查 | 循环体执行 之前 检查条件 | 循环体执行 之后 检查条件 |
首次执行 | 如果条件初始为 false ,循环体不执行 | 循环体 至少执行一次 |
语法 | while (condition) { ... } | do { ... } while (condition); (末尾有分号) |
三、while 循环与 for 循环:如何选择?
我们现在已经学习了 for
、while
和 do...while
三种主要的循环结构。那么在实际开发中,应该如何选择呢?
3.1 何时使用 for 循环?
for
循环是以下情况的首选:
- 迭代次数已知或固定:当你明确知道循环需要执行多少次时(例如,遍历数组的所有元素,或者重复操作 N 次)。
- 包含清晰的初始化、条件和迭代表达式:
for
循环的头部结构for (initializer; condition; iterator)
非常适合管理这三个部分。
// 遍历数组
const fruits = ["apple", "banana", "cherry"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// 执行固定次数的操作
for (let j = 0; j < 3; j++) {
console.log("执行第 " + (j + 1) + " 次操作");
}
3.2 何时使用 while 或 do…while 循环?
while
和 do...while
循环更适合以下情况:
- 迭代次数未知,依赖于动态条件:当循环的持续执行取决于某个在循环过程中可能发生变化的条件时(例如,等待用户输入、处理流数据直到结束标志出现、游戏主循环等)。
while
:如果可能存在循环体一次都不需要执行的情况(先判断条件)。do...while
:如果循环体至少需要执行一次(先执行后判断)。
// while: 等待特定条件成立
let isLoggedIn = false;
let attempts = 0;
const maxAttempts = 3;
while (!isLoggedIn && attempts < maxAttempts) {
console.log(`尝试登录,第 ${attempts + 1} 次`);
// 模拟登录逻辑
if (Math.random() > 0.5) { // 假设有50%几率登录成功
isLoggedIn = true;
console.log("登录成功!");
} else {
console.log("登录失败。");
}
attempts++;
}
if (!isLoggedIn) {
console.log("登录尝试次数过多!");
}
// do...while: 至少提示一次
let confirmation;
do {
// confirmation = prompt("你确定要删除吗?(yes/no)"); // 浏览器环境
const readlineSync = require('readline-sync');
confirmation = readlineSync.question("你确定要删除吗?(yes/no) ");
} while (confirmation !== 'yes' && confirmation !== 'no');
console.log(`你的选择是: ${confirmation}`);
3.3 代码可读性考量
虽然很多情况下 for
和 while
可以互换(例如,通过在 while
循环外部和内部手动管理计数器),但选择更符合场景语义的循环结构可以提高代码的可读性和意图的清晰性。
四、循环的“交通指挥”:break 与 continue
有时,在循环执行过程中,我们可能需要更精细地控制循环流程,而不是简单地等待循环条件自然变为 false
。这时,break
和 continue
语句就派上用场了。它们可以用于 for
、while
和 do...while
循环。
4.1 break 语句:立即跳出循环
4.1.1 概念与作用
break
语句用于立即终止其所在的最内层循环(for
、while
、do...while
)或 switch
语句的执行。一旦遇到 break
,程序将跳出该循环结构,继续执行循环之后的代码。
4.1.2 break
在 while
中的应用示例
假设我们想在一个数字序列中查找第一个能被 7 整除的数:
let number = 1;
let foundNumber = -1;
while (true) { // 使用 true 作为条件,依赖内部 break 来终止
if (number % 7 === 0) {
foundNumber = number;
console.log(`找到了第一个能被 7 整除的数: ${foundNumber}`);
break; // 找到后立即跳出循环
}
number++;
if (number > 100) { // 添加一个上限,防止意外的无限循环
console.log("搜索范围超过 100,未找到。");
break;
}
}
console.log("循环外部,foundNumber 是: " + foundNumber);
代码解析:
- 我们设置了一个
while(true)
的潜在无限循环,因为我们不知道何时能找到目标数字。 - 在循环体内,检查
number
是否能被 7 整除。 - 如果条件满足,我们将
foundNumber
记录下来,并使用break
语句立即退出while
循环。 - 为了安全起见,添加了一个当
number
超过 100 时也break
的条件,防止在某些意外情况下(比如没有符合条件的数字)程序无限运行。
4.2 continue 语句:跳过本次迭代
4.2.1 概念与作用
continue
语句用于跳过当前循环迭代中尚未执行的剩余代码,并立即开始下一次迭代。
- 在
while
和do...while
循环中,执行continue
后,程序会直接跳转到循环条件的判断。 - 在
for
循环中,执行continue
后,程序会先执行迭代表达式(例如i++
),然后再进行条件判断。
4.2.2 continue
在 while
中的应用示例
假设我们想打印 1 到 10 之间所有的奇数:
let num = 0;
while (num < 10) {
num++; // 先增加 num,确保条件最终会改变
if (num % 2 === 0) { // 如果 num 是偶数
continue; // 跳过本次迭代的 console.log,直接开始下一次迭代
}
console.log("奇数: " + num);
}
代码解析:
num
从 0 开始,每次循环先自增 1。- 如果
num
是偶数(num % 2 === 0
),则执行continue
语句。这将导致console.log("奇数: " + num);
这一行被跳过,循环直接进入下一次迭代(即重新判断num < 10
)。 - 如果
num
是奇数,则正常打印。 - 输出结果会是:1, 3, 5, 7, 9。
重要提示: 在 while
和 do...while
循环中使用 continue
时要特别小心。确保在 continue
语句之前或作为条件判断的一部分,用于循环条件的变量已经被更新。否则,如果 continue
跳过了更新条件变量的代码,也可能导致无限循环。
例如,下面这个修改后的例子就会产生无限循环:
// 错误的示例:使用 continue 导致的无限循环
let val = 0;
while (val < 10) {
if (val % 2 === 0) {
continue; // 如果 val 是偶数,跳过 val++
// val 将一直是0,0%2===0,无限continue
}
console.log("奇数: " + val);
val++; // 更新语句被跳过了!
}
正确的做法是像上一个示例一样,在 continue
之前就更新 val
。
4.3 break 与 continue 的对比
特性 | break 语句 | continue 语句 |
---|---|---|
作用 | 完全终止整个循环的执行 | 终止当前迭代,开始下一次迭代 |
跳转位置 | 跳转到循环结构之后的下一条语句 | 跳转到循环条件的判断(while /do...while )或迭代表达式(for ) |
影响范围 | 影响整个循环 | 仅影响当前迭代 |
五、常见问题与最佳实践 (FAQ & Tips)
5.1 如何避免 while
和 do...while
中的死循环?
- 确保条件变量会被更新:在循环体内部,必须有代码能改变循环条件中涉及的变量,使其最终能够导致条件为
false
。 - 仔细检查循环条件:确保条件逻辑正确,不会永远为
true
。 - 使用
break
作为安全出口:对于可能复杂的循环,或while(true)
结构,确保有明确的break
条件。 - 测试边界条件:思考循环开始、进行中和结束时的各种状态。
5.2 while(true)
的使用场景?
while(true)
(或 while(1)
)会创建一个显式的无限循环。这看起来很危险,但它在某些情况下是有用的,前提是循环体内部必须有 break
语句来在某个条件满足时终止循环。
常见场景:
- 事件监听或服务:某些持续运行的后台服务或监听器可能会使用这种模式,等待事件发生然后处理,并通过特定信号
break
。 - 游戏主循环:游戏通常有一个主循环,不断更新游戏状态、渲染画面,直到用户选择退出。
- 需要复杂退出逻辑的循环:当退出循环的条件不止一个,并且这些条件在循环体的不同位置判断更方便时。
let command = "";
const readlineSync = require('readline-sync');
while (true) {
command = readlineSync.question("输入命令 (type 'exit' to quit): ");
if (command === "hello") {
console.log("Hello there!");
} else if (command === "time") {
console.log(new Date().toLocaleTimeString());
} else if (command === "exit") {
console.log("正在退出...");
break; // 退出条件
} else {
console.log("未知命令.");
}
}
console.log("程序已终止。");
5.3 循环条件的清晰性
编写易于理解的循环条件至关重要。复杂的条件可以考虑拆分或使用辅助布尔变量来提高可读性。
// 不那么清晰
// while ((x < 10 && y > 0 && !isValid) || forceContinue) { ... }
// 更清晰
let condition1 = x < 10 && y > 0 && !isValid;
let shouldLoop = condition1 || forceContinue;
// while (shouldLoop) { ... }
// 在循环内部更新 x, y, isValid, forceContinue, 并重新计算 shouldLoop (或者直接在while条件中判断)
当然,在 while
条件中直接写也是常见的,关键是平衡简洁性和可读性。
六、总结
在本篇文章中,我们详细探讨了 JavaScript 中的 while
和 do...while
循环,以及循环控制语句 break
和 continue
。
以下是核心知识点回顾:
-
while
循环:- 语法:
while (condition) { /* code */ }
- 特点:先判断条件,条件为
true
才执行循环体。如果条件初始为false
,则一次也不执行。 - 适用:循环次数未知,依赖条件判断,且可能一次都不执行的场景。
- 语法:
-
do...while
循环:- 语法:
do { /* code */ } while (condition);
(注意末尾分号) - 特点:先执行一次循环体,然后判断条件,条件为
true
则继续循环。循环体至少执行一次。 - 适用:循环次数未知,但至少需要执行一次操作的场景(如菜单提示)。
- 语法:
-
选择循环类型:
for
:迭代次数已知或易于计算。while
:迭代次数未知,先判断。do...while
:迭代次数未知,至少执行一次。
-
循环控制:
break
:立即终止整个循环。continue
:跳过当前迭代的剩余部分,开始下一次迭代。使用时需注意条件变量的更新,避免死循环。
-
避免无限循环:
- 始终确保循环条件相关的变量在循环体内得到适当更新,以便循环最终能够结束。
- 对于
while(true)
结构,必须有可靠的break
路径。
通过掌握这些循环结构,你将能够更灵活地控制程序的流程,处理各种需要重复执行任务的场景。在下一篇文章中,我们将开始学习 JavaScript 中一个非常核心且强大的概念——函数,敬请期待!