JavaScript 条件与循环
程序最强大的地方,在于它能"根据情况做不同的事"(条件)和"重复干活"(循环)。这两类语句是编程的核心,这一章我们一次讲清楚。
1. if-else 条件语句
最基本的分支语句。条件为真就执行对应分支:
// if / else if / else
const score = 78;
if (score >= 90) {
console.log("优秀");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
// 输出: 及格
// 条件可以嵌套
const age = 20;
const hasTicket = true;
if (age >= 18) {
if (hasTicket) {
console.log("欢迎入场");
} else {
console.log("请先购票");
}
}
// 单行 if 也可以省 {},但不推荐(可读性差)
if (true) console.log("ok");注意:JS 的 if 判断时会把条件转成布尔——所以 if (0)、if ("")、if (null) 都是 false,而 if ("0")、if ([]) 反而是 true(非空字符串和对象是真值)。
2. switch 多分支
当条件是"等于某个值",而且分支特别多时,用 switch 比 if-else 链更清晰。但有个大坑:必须写 break!
// switch:多分支选择,匹配 case 后,会一直执行直到 break
const day = "周三";
switch (day) {
case "周一":
case "周二":
case "周三":
case "周四":
case "周五":
console.log("工作日");
break; // 必须写,否则会"穿透"到下面
case "周六":
case "周日":
console.log("周末");
break;
default:
console.log("未知");
}
// 输出: 工作日
// ⚠️ 忘记 break 会"穿透"——执行后续所有 case 直到 break
const x = 1;
switch (x) {
case 1:
console.log("一");
case 2:
console.log("二");
case 3:
console.log("三");
break;
}
// 输出: 一 二 三(穿透了!)switch 的"穿透"(fall-through)特性有时被故意利用——比如多个 case 共享同一段代码(上面"周一"到"周五"都执行同一段)。但99% 的情况下是忘记写 break 导致的 bug。新项目里其实更推荐用对象映射代替 switch。
另外 switch 用的是 === 严格比较,不会做类型转换。
3. for 循环
经典的 C 风格 for 循环,适合已知次数的循环:
// 经典 for 循环:初始化;条件;更新
for (let i = 0; i < 3; i++) {
console.log(`第 ${i} 次`);
}
// 输出: 第 0 次 / 第 1 次 / 第 2 次
// 累加求和
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
console.log(sum); // 5050
// 倒序
for (let i = 3; i > 0; i--) {
console.log(i); // 3 / 2 / 1
}
// 省略任意一段(但要用 break 防止死循环)
let n = 0;
for (;;) {
if (n >= 3) break;
console.log(n);
n++;
}循环变量用 let 不能用 var(后者会泄漏到外层作用域,前面变量章节讲过)。如果循环体里用了 setTimeout 这类异步,务必用 let 才能正确捕获每轮的值。
4. while 与 do-while
当循环次数不确定、靠"条件满足才结束"时,用 while:
// while:先判断后执行(可能一次都不执行)
let i = 0;
while (i < 3) {
console.log(i);
i++;
}
// 输出: 0 / 1 / 2
// do-while:先执行后判断(至少执行一次)
let j = 0;
do {
console.log(j);
j++;
} while (j < 3);
// 实战:游戏循环、用户输入直到合法
let input;
do {
// input = prompt("请输入 yes 或 no");
input = "yes"; // 假设用户输入
} while (input !== "yes" && input !== "no");while:先判断后执行。条件一开始就不满足,可能一次都不执行。do-while:先执行后判断。至少执行一次。
注意别写出死循环(条件永远为真),会让页面卡死。常用的退出条件是用 break 或在条件里加边界。
5. break 和 continue
break:跳出整个循环,后面的轮次都不执行。continue:跳过当前轮,进入下一轮。
// break:跳出整个循环
for (let i = 0; i < 10; i++) {
if (i === 3) break; // i=3 时整个循环结束
console.log(i);
}
// 输出: 0 / 1 / 2
// continue:跳过本轮,进入下一轮
for (let i = 0; i < 5; i++) {
if (i % 2 === 0) continue; // 跳过偶数
console.log(i);
}
// 输出: 1 / 3
// 嵌套循环 + 标签 break(跳出外层)
outer:
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) break outer;
console.log(`(${i},${j})`);
}
}
// 输出: (0,0) (0,1) (0,2) (1,0)JS 还支持标签 break(上面例子里的 break outer),用来跳出多层嵌套循环。但实际开发用得不多——通常是把内层循环抽成一个函数,直接 return。
6. for-of:遍历数组的首选
ES6 引入的 for-of 是遍历可迭代对象(数组、字符串、Map、Set)的现代方式:
// for-of:遍历"可迭代对象"(数组、字符串、Map、Set),ES6
const arr = ["a", "b", "c"];
for (const item of arr) {
console.log(item);
}
// 输出: a / b / c
// 想同时拿索引,用 entries()
for (const [index, item] of arr.entries()) {
console.log(index, item);
}
// 输出: 0 a / 1 b / 2 c
// 遍历字符串
for (const ch of "hi") {
console.log(ch); // h / i
}
// for-in:遍历对象的"可枚举属性"(包括继承的)
const user = { name: "小明", age: 20 };
for (const key in user) {
console.log(key, user[key]);
}
// 输出: name 小明 / age 20
// ⚠️ for-in 不适合遍历数组:它会遍历所有可枚举属性,顺序不保证
// 数组永远用 for-of 或 forEach,不要用 for-infor-of vs for-in 一句话区分:
- for-of:遍历值,用于数组/字符串等可迭代对象。
- for-in:遍历键,用于对象。不要用来遍历数组(顺序不保证,还会带上自定义属性)。
7. 实战:遍历数组的几种方式
const nums = [10, 20, 30];
// 1. for-of(最推荐,简洁)
for (const n of nums) {
console.log(n);
}
// 2. 经典 for(需要索引时用)
for (let i = 0; i < nums.length; i++) {
console.log(i, nums[i]);
}
// 3. forEach(简单遍历,但不能 break)
nums.forEach((n, i) => {
console.log(i, n);
});
// 4. map(把每个元素转成新数组)
const doubled = nums.map(n => n * 2);
console.log(doubled); // [20, 40, 60]
// 5. filter(筛选满足条件的)
const big = nums.filter(n => n > 15);
console.log(big); // [20, 30]
// 6. reduce(汇总成一个值)
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // 60现代 JS 中,map、filter、reduce 用得极多,后面"数组"一章会详讲。
8. 常见陷阱
- 死循环:忘记更新循环变量,导致条件永远为真。
- off-by-one:循环多/少一次。如
for (let i = 0; i <= arr.length; i++)——应该是<。 - 循环里用 var:用
let替换,作用域才正确。 - 循环里改数组长度:边遍历边增删元素会出错,建议先复制再改。
小结
- 条件用
if-else,多分支可以用switch或对象映射。 - 已知次数用
for,未知次数用while。 - 遍历数组用
for-of或forEach;遍历对象用for-in或Object.entries()。 break跳出,continue跳过。
下一篇我们看 JS 的函数——把代码封装成可复用的"积木块"。
← 上一篇 JavaScript 运算符
下一篇 JavaScript 函数 →