条件判断与循环
上一节已经能判断成绩是否合法。接下来要让无效成绩停止分级,把有效成绩 86 显示为“良好”、52 显示为“需要补考”,还要显示学员状态并统计多名学员的合格人数。本节先处理一名学员的条件分支,再用循环批量处理。
条件分支
if 单分支与双分支
const score = 86;
if (score >= 60) {
console.log("成绩合格");
}圆括号中是条件,条件为真时执行花括号内的代码。即使当前只有一行,课程仍保留花括号。
if 没有 else 时,条件为假就直接跳过代码块。
如果还要处理不合格的情况,可以增加 else:
const score = 52;
if (score >= 60) {
console.log("成绩合格");
} else {
console.log("需要补考");
}两个分支只会执行一个。
成绩分级
const scoreText = "86";
const score = Number(scoreText);
const isValidScore =
scoreText.trim() !== "" && Number.isFinite(score) && score >= 0 && score <= 100;
let level;
if (!isValidScore) {
level = "成绩无效";
} else if (score >= 90) {
level = "优秀";
} else if (score >= 80) {
level = "良好";
} else if (score >= 60) {
level = "合格";
} else {
level = "需要补考";
}
console.log(level);先用上一节的规则排除空值、非数字和超出范围的成绩,再进行分级。把 scoreText 改为 "86分" 或 " ",应输出“成绩无效”,而不是误判为“需要补考”。条件从上到下检查,遇到第一个为真的分支后停止;成绩范围从高到低写,避免 95 先被 score >= 60 拦截。
下图把“从上到下、命中即停止”展开了。一旦某个条件成立,程序就不会再进入后面的分支。
switch 状态匹配
当一个值需要与多个明确选项比较时,可以使用 switch:
const status = "pending";
let statusText;
switch (status) {
case "active":
statusText = "正常";
break;
case "pending":
statusText = "待审核";
break;
case "disabled":
statusText = "已停用";
break;
default:
statusText = "未知状态";
}
console.log(statusText);break 结束当前 switch,阻止继续执行后面的 case。default 处理没有匹配的值。匹配时不会隐式转换类型,例如数字 1 不会匹配字符串 "1"。
每个 case 都是一个固定值入口;break 让当前分支处理完后直接离开 switch。
switch 适合离散的相等比较;成绩范围使用 if...else if 更直接。不要用“谁性能更好”作为基础选择依据,先看表达是否清楚。
三元表达式
简单的二选一可以写成:
const score = 86;
const resultText = score >= 60 ? "合格" : "不合格";
console.log(resultText); // "合格"复杂的多层判断不要嵌套多个三元运算符,改用 if 或函数。
循环遍历
for 索引遍历
for (let index = 0; index < 3; index += 1) {
console.log(`当前索引:${index}`);
}三个部分分别表示:
let index = 0:循环开始前执行一次。index < 3:每轮开始前判断。index += 1:每轮结束后执行。
用索引处理数组:
先认识循环所需的最小数组写法:方括号保存一组值,索引从 0 开始,students[0] 读取第一项,students.length 表示项数。数组的新增、删除和其他操作在下一节学习。
const students = ["张三", "李四", "王五"];
for (let index = 0; index < students.length; index += 1) {
console.log(`${index + 1}. ${students[index]}`);
}for...of 元素遍历
只关心数组元素时,for...of 更简洁:
const scores = [86, 72, 93];
let total = 0;
for (const score of scores) {
total += score;
}
console.log(total);这里依次读到 86、72、93,total 从 0 变为 86、158、251。每轮声明的 score 只表示当前这一项,不是整个数组。
for...of 每轮得到一个值。不要用 for...in 遍历数组元素;它得到的是可枚举属性名,语义不同。
for...of 会自动取出下一个值,所以不需要自己维护 index。
while 条件循环
不知道确切循环次数,只知道继续条件时使用 while:
let remainingSeats = 3;
while (remainingSeats > 0) {
console.log(`剩余名额:${remainingSeats}`);
remainingSeats -= 1;
}必须确保条件最终会变为假,否则会形成无限循环。
for 和 while 的写法不同,但执行都会回到“再次检查条件”。下图使用 for 的索引变量展示这个闭环:
如果忘记 index += 1,条件可能一直为真。while 中同样要有能让条件逐步接近结束的操作。
循环控制
break 终止循环
找到目标后立即结束循环:
下面把姓名和编号放在同一对花括号中,组成一条学员记录;student.id 表示读取当前记录的编号。现在先理解循环怎样逐条查找,记录的完整组织方式放到下一节。
const students = [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" },
{ id: 3, name: "王五" },
];
let targetStudent = null;
for (const student of students) {
if (student.id === 2) {
targetStudent = student;
break;
}
}
console.log(targetStudent);这里的 break 结束当前 for 循环,前面 switch 中的 break 只结束当前 switch。如果把 switch 写在循环内,switch 的 break 不会结束外层循环。数组后面会学习 find(),但理解循环的 break 有助于读懂一般循环。
continue 跳过当前轮
跳过当前轮次,继续下一轮:
const students = [
{ name: "张三", status: "active" },
{ name: "李四", status: "disabled" },
{ name: "王五", status: "active" },
];
for (const student of students) {
if (student.status !== "active") {
continue;
}
console.log(student.name);
}break 和 continue 都会改变默认循环流程,但去向不同:
break的出口是“循环之外”。continue的出口是“下一轮循环”。
学员成绩与状态处理
本例约定成绩已经是 0 到 100 之间的有效数字,非法输入先按上一节的方法处理。合格人数统计所有记录,不按学员状态排除。
const students = [
{ name: "张三", score: 86, status: "active" },
{ name: "李四", score: 52, status: "active" },
{ name: "王五", score: 93, status: "disabled" },
{ name: "赵敏", score: 78, status: "pending" },
];
let passedCount = 0;
for (const student of students) {
let level;
if (student.score >= 90) {
level = "优秀";
} else if (student.score >= 80) {
level = "良好";
} else if (student.score >= 60) {
level = "合格";
} else {
level = "需要补考";
}
let statusText;
switch (student.status) {
case "active":
statusText = "正常";
break;
case "pending":
statusText = "待审核";
break;
case "disabled":
statusText = "已停用";
break;
default:
statusText = "未知";
}
if (student.score >= 60) {
passedCount += 1;
}
console.log(`${student.name}:${level},状态:${statusText}`);
}
console.log(`合格人数:${passedCount}`);综合案例的外层是“遍历学员”,内层才是成绩和状态判断。先看清一名学员的处理顺序,再理解整个循环:
练习与验收
运行综合案例,应得到张三“良好”、李四“需要补考”、王五“优秀”、赵敏“合格”,合格人数为 3。
- 把李四的成绩改为
60,应变为“合格”,合格人数变为4。 - 从原始数据重新开始,在循环开头用
continue跳过非active学员,应只处理张三和李四。此时只统计正常状态学员,其中合格人数为1。 - 将查找示例的目标编号改为不存在的
99,结果应保留为null。 - 在
switch示例中把状态改为"archived",应输出“未知状态”;在while示例中把remainingSeats设为0,循环体应执行0次。
说明循环中的 break 是否结束整个当前循环,以及 continue 跳过了本轮哪些语句。下一节正式学习数组与对象,用同一套结构组织这些学员记录。
小结
if...else适合范围和组合条件,switch适合离散相等分支。- 分支顺序会影响结果,数据验证通常放在业务判断之前。
for适合需要索引的循环,for...of适合直接读取集合值。while要确保条件最终结束。break结束当前switch或循环,continue跳过当前轮次剩余语句。