JavaScript 条件判断与循环
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
条件与循环的语法本身很短,但选错写法会带来「遍历结果不对」「break 不生效」「遍历到了原型上的属性」这类问题。这一篇讲选择依据。
if / else 与三元表达式
const score = 85;
if (score >= 90) {
console.log("优秀");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
只有两个分支且都用于取值时,三元表达式更紧凑:
const label = score >= 60 ? "及格" : "不及格";
嵌套三元超过一层就该换回 if,可读性优先。
switch 适合等值匹配
const status = "pending";
switch (status) {
case "pending":
console.log("等待处理");
break;
case "done":
console.log("已完成");
break;
default:
console.log("未知状态");
}
两个必须记住的点:
switch用的是===比较,"1"不匹配1。- 每个 case 结尾必须写
break,否则会继续执行下一个 case(称为 fall-through)。刻意的 fall-through 要写注释说明。
for:需要索引时用
const names = ["ann", "bob", "cindy"];
for (let i = 0; i < names.length; i++) {
console.log(i, names[i]);
}
缓存数组长度(const len = names.length)在现代引擎里已经没有明显收益,不必为性能牺牲可读性。
for…of:只取值时用(推荐)
for (const name of names) {
console.log(name);
}
for...of 遍历的是值,适用于数组、字符串、Set、Map 等可迭代对象。它比 for 更短,也不会出现索引越界。
需要索引时配合 entries():
for (const [i, name] of names.entries()) {
console.log(i, name);
}
for…in:不要用来遍历数组
for...in 遍历的是可枚举的属性名(键),并且会包含原型链上的属性:
const arr = ["a", "b"];
arr.custom = "x";
for (const key in arr) {
console.log(key); // "0", "1", "custom"
}
遍历数组用 for...of 或数组方法;for...in 只在遍历普通对象的键时才考虑,且通常配合 Object.hasOwn() 过滤:
const user = { name: "ann", age: 30 };
for (const key in user) {
if (Object.hasOwn(user, key)) {
console.log(key, user[key]);
}
}
更推荐直接用 Object.keys(user) / Object.entries(user) 转成数组后遍历,见本系列第 6 篇。
while 与 do…while
while 用于次数不确定的循环:
let retry = 0;
while (retry < 3) {
console.log(`第 ${retry + 1} 次尝试`);
retry++;
}
do...while 保证至少执行一次,适合「先做一次,再判断是否继续」的场景,例如「先读取一次输入,输入不合法就重读」。
忘记更新循环变量会造成死循环,写 while 时先确认退出条件一定会到达。
break 与 continue
for (const n of [1, 2, 3, 4, 5]) {
if (n === 2) continue; // 跳过本次,继续下一轮
if (n === 4) break; // 直接结束整个循环
console.log(n);
}
// 输出:1 3
需要注意:forEach 里 break 和 continue 都是非法的。
[1, 2, 3].forEach((n) => {
if (n === 2) break; // SyntaxError: Illegal break statement
});
forEach 的回调里想跳过某项只能 return(相当于 continue);想提前结束整个遍历,改用 for...of + break,或用 some() / every() / find() 这类自带短路语义的方法。
标签:跳出嵌套循环
outer:
for (const row of [[1, 2], [3, 4]]) {
for (const n of row) {
if (n === 3) break outer; // 直接跳出两层
console.log(n);
}
}
// 输出:1 2
标签语法少见,但确有多层跳出需求时比「设置标志变量」干净得多。
一个完整例子:统计与查找
const orders = [
{ id: 1, amount: 120, paid: true },
{ id: 2, amount: 80, paid: false },
{ id: 3, amount: 200, paid: true },
];
let total = 0;
let firstUnpaid = null;
for (const order of orders) {
if (!order.paid) {
firstUnpaid ??= order; // 只记录第一个未支付订单
continue;
}
total += order.amount;
}
console.log(total); // 320
console.log(firstUnpaid.id); // 2
常见错误与注意事项
switch忘记break:会连续执行后续分支,结果是「同时命中多个」。- 用
for...in遍历数组:会拿到字符串类型的下标和额外属性,排序也不保证。 - 在
forEach里写break:语法错误,用for...of或some()/find()。 while循环变量没更新:死循环,脚本卡死。- 在遍历数组的同时
splice删除元素:下标会错位,漏掉元素。用filter()生成新数组。
小结
- 要索引用
for或entries(),只要值用for...of。 for...in遍历键,不用于数组。switch是===比较,记得break。forEach不能中断,需要中断就用for...of或some()/find()。