lesson59:JavaScript 控制流详解:分支结构与循环语句全指南

发布于:2025-09-14 ⋅ 阅读:(10) ⋅ 点赞:(0)

目录

一、分支结构:让程序学会"做选择"

1. if 语句:灵活的条件判断

1.1 常见形式与应用场景

1.2 嵌套 if 与注意事项

2. switch 语句:多值匹配的高效方案

2.1 核心特性与示例

2.2 if-else vs switch:如何选择?

二、循环语句:高效处理重复任务

1. for 循环:最经典的计数循环

1.1 执行流程解析

1.2 基础用法与变种

2. while 循环:条件驱动的循环

2.1 典型应用场景

2.2 警惕无限循环!

3. do-while 循环:至少执行一次的循环

3.1 适用场景:先执行后判断

4. 现代循环:for...of 与 for...in(ES6+)

4.1 for...of:遍历可迭代对象

4.2 for...in:遍历对象属性

5. 循环选择指南:哪种循环最适合你?

三、循环控制与高级技巧

1. 循环控制语句:break 与 continue

2. 标签语句:跳出多层循环

3. 性能优化:减少循环开销

四、总结与最佳实践

核心知识点回顾

编写高质量代码的建议


在 JavaScript 编程中,控制流是构建逻辑的核心。无论是根据用户输入展示不同内容,还是处理大量数据,都离不开分支结构循环语句的灵活运用。本文将系统讲解 JavaScript 中的分支结构(if/switch)与循环语句(for/while/do-while),结合实例分析其适用场景与最佳实践,帮助你写出更高效、更可读的代码。

一、分支结构:让程序学会"做选择"

分支结构允许程序根据不同条件执行不同代码块,是实现"决策逻辑"的基础。JavaScript 提供两种主要分支结构:if 语句switch 语句

1. if 语句:灵活的条件判断

if 语句是最常用的分支结构,通过布尔条件决定代码执行路径。其基本语法如下:

// 基础语法
if (条件表达式) {
// 条件为 true 时执行
} else if (条件表达式2) {
// 条件1为 false,条件2为 true 时执行
} else {
// 所有条件都为 false 时执行
}
1.1 常见形式与应用场景
  • 单条件判断(if):适用于单一条件场景,如用户登录验证

    const isLoggedIn = checkUserStatus();
    if (isLoggedIn) {
    renderDashboard(); // 用户已登录,渲染控制台
    }
  • 二选一判断(if-else):处理互斥条件,如权限控制

    if (user.role === 'admin') {
    showAdminPanel(); // 管理员显示管理面板
    } else {
    showUserPanel(); // 普通用户显示用户面板
    }
  • 多条件判断(if-else if-else):处理多种可能结果,如成绩评级

    const score = 85;
    if (score >= 90) {
    console.log('优秀');
    } else if (score >= 80) {
    console.log('良好'); // 输出:良好
    } else if (score >= 60) {
    console.log('及格');
    } else {
    console.log('不及格');
    }
1.2 嵌套 if 与注意事项

嵌套 if 可处理复杂条件,但过度嵌套会导致"回调地狱"式的代码(如 if (a) { if (b) { if (c) { ... } } })。建议:

  • 条件合并:用逻辑运算符(&&/||/!)简化多层条件
  • 提前返回:将简单条件放在前面,减少嵌套层级
  • 使用三元表达式:处理简单二选一逻辑(但避免嵌套三元)
// 优化前:嵌套 if
if (user) {
if (user.isVerified) {
if (user.hasPermission) {
allowAccess();
} else {
showError('无权限');
}
} else {
showError('未验证');
}
} else {
showError('未登录');
}


// 优化后:提前返回 + 条件合并
if (!user) return showError('未登录');
if (!user.isVerified) return showError('未验证');
if (!user.hasPermission) return showError('无权限');
allowAccess();

2. switch 语句:多值匹配的高效方案

当需要根据固定值执行不同逻辑时,switch 比 if-else 更简洁。其语法结构如下:

switch (表达式) {
case 值1:
// 表达式 === 值1 时执行
break; // 跳出 switch
case 值2:
// 表达式 === 值2 时执行
break;
default:
// 所有 case 不匹配时执行(可选)
}
2.1 核心特性与示例
  • 严格匹配:使用 === 比较,类型和值必须完全一致
  • case 穿透:缺少 break 会继续执行下一个 case(可利用此特性合并逻辑)
  • default 子句:处理未匹配的情况,建议始终添加以避免逻辑遗漏
// 根据月份判断季节(利用穿透特性)
const month = 3;
switch (month) {
case 12:
case 1:
case 2:
console.log('冬季');
break;
case 3: // 3月匹配此 case,因无 break 会穿透到 case 4
case 4:
case 5:
console.log('春季'); // 输出:春季
break;
case 6:
case 7:
case 8:
console.log('夏季');
break;
case 9:
case 10:
case 11:
console.log('秋季');
break;
default:
console.log('无效月份');
}
2.2 if-else vs switch:如何选择?

场景 推荐使用 原因
范围条件(如 x > 10 if-else switch 仅支持固定值匹配,不支持范围判断
固定值匹配(如状态码) switch 代码更简洁,避免冗长的 else if (x === value)
少量条件(≤3个) if-else 无需额外语法(break/default),可读性更高
多条件且值离散 switch 执行效率更高(引擎可优化为跳转表),且逻辑分组更清晰

二、循环语句:高效处理重复任务

循环语句用于重复执行代码块,是处理数组、集合等数据的必备工具。JavaScript 提供四种循环方式:forwhiledo-whilefor...of/for...in(ES6+)。

1. for 循环:最经典的计数循环

for 循环适合已知循环次数的场景,语法结构清晰,控制力强:

for (初始化表达式; 条件表达式; 增量表达式) {
// 循环体
}
1.1 执行流程解析
  1. 初始化:执行一次(如 let i = 0
  2. 条件判断:若为 true,执行循环体;否则退出循环
  3. 增量更新:执行循环体后更新变量(如 i++
  4. 重复步骤 2-3
1.2 基础用法与变种
  • 标准 for 循环:遍历数组(最常用场景)

    const fruits = ['苹果', '香蕉', '橙子'];
    for (let i = 0; i < fruits.length; i++) {
    console.log(`第${i+1}个水果:${fruits[i]}`);
    }
    // 输出:
    // 第1个水果:苹果
    // 第2个水果:香蕉
    // 第3个水果:橙子
  • 反向循环:从数组末尾开始遍历

    for (let i = fruits.length - 1; i >= 0; i--) {
    console.log(fruits[i]); // 橙子、香蕉、苹果
    }
  • 跳过/终止循环:使用 continue(跳过当前迭代)和 break(终止整个循环)

    // 求1-100间偶数之和(跳过奇数)
    let sum = 0;
    for (let i = 1; i <= 100; i++) {
    if (i % 2 !== 0) continue; // 跳过奇数
    sum += i;
    if (sum > 1000) break; // 超过1000时提前终止
    }
    console.log(sum); // 1050(1+3+...+45=1035,+47=1082>1000,故终止于46的和1015?需计算验证)
  • 无限循环:需谨慎使用,必须在循环体内有退出条件

    for (;;) { // 等价于 while(true)
    const input = prompt('输入"quit"退出');
    if (input === 'quit') break;
    console.log('你输入了:', input);
    }

2. while 循环:条件驱动的循环

while 循环适合循环次数不确定的场景,仅在条件为 true 时执行:

while (条件表达式) {
// 循环体(需包含条件更新逻辑,避免无限循环)
}
2.1 典型应用场景
  • 等待某个条件满足:如轮询等待数据加载完成

    let data = null;
    while (!data) {
    data = fetchData(); // 假设 fetchData() 可能返回 null
    if (!data) await sleep(1000); // 未获取到数据,等待1秒重试
    }
    processData(data);
  • 用户输入验证:确保输入符合要求

    let age;
    while (isNaN(age) || age < 0 || age > 120) {
    age = Number(prompt('请输入有效年龄(0-120):'));
    }
    console.log('你的年龄是:', age);
2.2 警惕无限循环!

while 循环最常见的错误是条件永远为 true,导致浏览器卡死。避免方式:

  • 确保循环体内有修改条件的逻辑(如 count++
  • 添加安全机制(如最大重试次数):
    let retryCount = 0;
    while (retryCount < 5) { // 最多重试5次
    if (connect()) break;
    retryCount++;
    await sleep(1000);
    }
    if (retryCount === 5) console.error('连接失败');

3. do-while 循环:至少执行一次的循环

do-while 是后测试循环,无论条件如何,循环体至少执行一次

do {
// 循环体
} while (条件表达式); // 注意末尾分号
3.1 适用场景:先执行后判断
  • 初始化操作:如加载配置文件,即使配置为空也需执行一次解析
  • 菜单交互:确保用户至少看到一次菜单选项
    let choice;
    do {
    console.log(`1. 查看信息\n2. 修改信息\n3. 退出`);
    choice = prompt('请选择操作(1-3):');
    switch (choice) {
    case '1': showInfo(); break;
    case '2': editInfo(); break;
    case '3': console.log('退出程序'); break;
    default: alert('无效选项');
    }
    } while (choice !== '3'); // 选择3时退出

4. 现代循环:for...of 与 for...in(ES6+)

ES6 引入了更简洁的循环语法,尤其适合遍历数据集合。

4.1 for...of:遍历可迭代对象

用于遍历数组、字符串、Map、Set等可迭代对象(Iterable),直接获取值而非索引:

// 遍历数组
const numbers = [10, 20, 30];
for (const num of numbers) {
console.log(num * 2); // 20、40、60
}


// 遍历字符串
for (const char of 'hello') {
console.log(char.toUpperCase()); // H、E、L、L、O
}


// 遍历 Map
const user = new Map([['name', '张三'], ['age', 25]]);
for (const [key, value] of user) {
console.log(`${key}: ${value}`); // name: 张三,age: 25
}
4.2 for...in:遍历对象属性

用于遍历对象的可枚举属性(包括继承的属性),返回属性名:

const person = { name: '李四', age: 30, city: '北京' };
for (const key in person) {
if (person.hasOwnProperty(key)) { // 过滤继承属性
console.log(`${key}: ${person[key]}`);
}
}
// 输出:
// name: 李四
// age: 30
// city: 北京

⚠️ 注意

  • 不要用 for...in 遍历数组(可能遍历到非数字索引的属性)
  • 始终用 hasOwnProperty 过滤原型链属性

5. 循环选择指南:哪种循环最适合你?

场景 推荐循环 优势
遍历数组(已知索引) for / for...of for 可控制步长(如 i+=2),for...of 更简洁
遍历对象属性 for...in 专门为对象属性设计,返回键名
遍历可迭代对象(Map/Set/字符串) for...of 直接获取值,支持解构赋值
循环次数不确定(条件控制) while 逻辑更清晰,避免冗余的初始化代码
至少执行一次 do-while 无需提前初始化条件变量
异步循环(如等待Promise) for...of + async/await 支持 await 语法(普通 for 循环也可)

三、循环控制与高级技巧

1. 循环控制语句:break 与 continue

  • break:立即终止整个循环,跳到循环后的代码

    // 查找数组中第一个偶数
    const nums = [1, 3, 5, 4, 7];
    let firstEven;
    for (const num of nums) {
    if (num % 2 === 0) {
    firstEven = num;
    break; // 找到后立即退出循环
    }
    }
    console.log(firstEven); // 4
  • continue:跳过当前迭代,直接进入下一次循环

    // 计算数组中奇数之和
    const nums = [1, 2, 3, 4, 5];
    let sum = 0;
    for (const num of nums) {
    if (num % 2 === 0) continue; // 跳过偶数
    sum += num;
    }
    console.log(sum); // 1+3+5=9

2. 标签语句:跳出多层循环

嵌套循环中,可通过标签语句跳出外层循环(不推荐过度使用,建议拆分为函数):

outerLoop: for (let i = 0; i < 3; i++) {
innerLoop: for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outerLoop; // 直接跳出 outerLoop
}
console.log(`i=${i}, j=${j}`);
}
}
// 输出:
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0(然后 break outerLoop)

3. 性能优化:减少循环开销

  • 缓存数组长度:避免每次循环都计算 arr.length

    // 优化前
    for (let i = 0; i < arr.length; i++) { ... }
    
    
    // 优化后
    for (let i = 0, len = arr.length; i < len; i++) { ... }
  • 避免在循环中操作 DOM:DOM 操作昂贵,建议批量处理

    // 优化前(每次循环操作DOM)
    for (const item of list) {
    document.getElementById('container').innerHTML += `<div>${item}</div>`;
    }
    
    
    // 优化后(先拼接字符串,再一次性更新)
    let html = '';
    for (const item of list) {
    html += `<div>${item}</div>`;
    }
    document.getElementById('container').innerHTML = html;
  • 使用 typedArray:处理大量数字时,Uint8Array 等类型数组比普通数组更快

四、总结与最佳实践

核心知识点回顾

  • 分支结构:用 if-else 处理灵活条件,switch 处理固定值匹配
  • 循环语句for 适合计数,while 适合条件控制,for...of 适合遍历数据
  • 控制流break 终止循环,continue 跳过迭代,标签语句处理嵌套循环

编写高质量代码的建议

  1. 可读性优先:避免过度嵌套(分支/循环),复杂逻辑拆分为函数
  2. 选择合适工具:根据场景选择分支/循环类型(如范围条件用 if,固定值用 switch)
  3. 防御性编程:循环添加边界条件,避免无限循环;分支添加 default 处理异常情况
  4. 利用现代语法:优先使用 for...ofconst/let 等 ES6+ 特性,减少 var 导致的作用域问题
  5. 代码复用:重复逻辑抽象为函数(如将循环逻辑封装为工具函数)

控制流是 JavaScript 的骨架,掌握分支与循环不仅能解决当前问题,更能培养结构化思维。通过大量实践(如实现排序算法、处理API数据),你将能灵活运用这些工具,写出高效、优雅的代码!

下一步学习建议:结合函数、数组方法(forEach/map/filter)深入理解声明式编程,对比命令式循环的优劣。


网站公告

今日签到

点亮在社区的每一天
去签到