零基础鸿蒙应用开发第七节:流程控制之分支语句
【学习目标】
- 理解流程控制的核心作用,掌握分支语句的本质(根据条件执行不同逻辑)
- 掌握
if-else分支语句的基础语法、嵌套用法及边界条件处理 - 掌握
switch语句的语法规则、break关键字的作用,理解穿透特性的使用场景 - 掌握三元运算符的语法与简写逻辑,区分其与
if-else的适用场景 - 能结合实际业务场景(成绩等级判断、订单状态处理、登录验证)选择合适的分支语句
【学习重点】
if-else的条件表达式结果必须是布尔值。switch语句中break不可省略(否则会触发穿透),default分支用于处理异常情况- 三元运算符仅适用于“二选一”的简单场景,复杂逻辑优先用
if-else - 嵌套
if-else需控制层级(建议不超过3层),提升代码可读性 - 明确三者适用场景:简单二选一用三元运算符,多条件等值判断用
switch,复杂条件判断用if-else
一、工程结构
本节我们将创建名为FlowControlBranchDemo的工程,基于鸿蒙5.0(API12)开发,使用DevEco Studio 6.0+工具,项目结构目录如下:
FlowControlBranchDemo
├── AppScope # 应用全局配置
├── entry # 主模块目录
│ ├── src
│ │ ├── main
│ │ │ ├── ets # ArkTS核心代码目录
│ │ │ │ ├── entryability # 应用入口能力
│ │ │ │ ├── pages # 页面组件目录
│ │ │ │ │ └── Index.ets # 核心页面(调用测试函数)
│ │ │ │ └── utils # 工具函数目录
│ │ │ │ └── FlowControlTest.ets # 本节所有学习内容
│ │ │ ├── resources # 静态资源(图片/字符串等)
│ │ │ └── module.json5 # 模块配置文件
│ │ ├── ohosTest # 鸿蒙测试目录
│ │ └── test # 单元测试目录
│ ├── build-profile.json5 # 构建配置
│ ├── hvigorfile.ts # 构建脚本
│ └── oh-package.json5 # 依赖配置
├── hvigor # 构建工具依赖
└── oh_modules # 第三方依赖包
开发准备步骤
- 打开DevEco Studio,创建
FlowControlBranchDemo项目(选择Empty Ability模板,API12/鸿蒙5.0); - 在
src/main/ets目录下右键创建utils文件夹; - 选中
utils文件夹,右键创建FlowControlTest.ets文件(封装所有分支语句测试函数); - 所有学习内容在
Index.ets的aboutToAppear生命周期中统一调用,无需额外配置。
二、流程控制核心概念:为什么需要分支语句?
在编程中,流程控制用于控制代码的执行顺序,而分支语句是流程控制的核心之一,解决“根据不同条件执行不同逻辑”的问题。
举个生活例子:
- 出门前看天气:如果下雨,带雨伞;否则,带太阳镜(二选一逻辑);
- 成绩评级:90分以上为A,80-89分为B,70-79分为C,否则为D(多条件逻辑);
- 订单支付:待支付→显示“支付按钮”,已支付→显示“待发货”,已取消→显示“重新下单”(多状态逻辑)。
这些场景都需要“根据条件做选择”,而分支语句(if-else/switch/三元运算符)就是编程中的“选择工具”。
三、if-else语句:复杂条件的灵活判断
if-else是最常用的分支语句,支持任意布尔条件判断,灵活应对简单到复杂的逻辑场景。
3.1 基础语法(二选一逻辑)
语法结构
if (条件表达式) {
// 条件为true时执行的代码块
} else {
// 条件为false时执行的代码块
}
- 条件表达式必须返回
boolean类型(true/false),直接用数字、字符串等非布尔值不会编译报错,但会触发隐式类型转换,极易导致逻辑错误; - 代码块
{}:当只有一行代码时可省略,但推荐始终保留(提升可读性,避免后续扩展出错)。
代码示例:基础if-else(成绩及格判断)
/**
* 测试基础if-else:成绩及格判断(二选一逻辑)
* 覆盖场景:常规及格分数、常规不及格分数,重点验证if/else两个分支的执行效果
*/
export function testIfElseBasic(): void {
console.log(`\n========== 基础if-else(成绩及格判断) ==========`);
// 场景1:常规及格分数(触发if分支)
const score: number = 85;
if (score >= 60) {
console.log(`分数:${score},结果:及格`);
} else {
console.log(`分数:${score},结果:不及格`);
}
// 场景2:常规不及格分数(触发else分支,对比边界值60分的核心场景)
const score2: number = 59;
if (score2 >= 60) {
console.log(`分数:${score2},结果:及格`);
} else {
console.log(`分数:${score2},结果:不及格`);
}
// 判断条件要严谨 如果我们只写 if (score > 60) 就会漏掉刚刚及格的60分
}
运行效果
========== 基础if-else(成绩及格判断) ==========
分数:85,结果:及格
分数:59,结果:不及格
3.2 多条件分支(if-else if-else)
当需要判断多个连续条件时,使用if-else if-else结构,按顺序执行条件判断,直到找到第一个为true的条件。
语法结构
if (条件1) {
// 条件1为true时执行
} else if (条件2) {
// 条件1为false,条件2为true时执行
} else if (条件3) {
// 条件1、2为false,条件3为true时执行
} else {
// 所有条件都为false时执行(可选)
}
代码示例:多条件if-else if-else(成绩等级判断)
/**
* 测试多条件if-else if-else:成绩等级判断(A/B/C/D)
*/
export function testIfElseMulti(): void {
console.log(`\n========== 多条件if-else if-else(成绩等级判断) ==========`);
const score: number = 78;
// 条件顺序:从高到低(需注意:顺序颠倒会导致逻辑错误)
if (score >= 90) {
console.log(`分数:${score},等级:A(优秀)`);
} else if (score >= 80) {
console.log(`分数:${score},等级:B(良好)`);
} else if (score >= 60) {
console.log(`分数:${score},等级:C(及格)`);
} else {
console.log(`分数:${score},等级:D(不及格)`);
}
// 错误示例(注释掉,可取消注释验证问题)
// const wrongScore: number = 85; // 补全显式类型标注
// if (wrongScore >= 60) { // 第一个条件就满足,后续条件不会执行
// console.log(`分数:${wrongScore},等级:C`); // 错误结果
// } else if (wrongScore >= 80) {
// console.log(`分数:${wrongScore},等级:B`);
// }
}
运行效果
========== 多条件if-else if-else(成绩等级判断) ==========
分数:78,等级:C(及格)
3.3 嵌套if-else(复杂逻辑分层判断)
当条件需要分层判断时(比如“先判断是否获取授权,再判断是否账号密码”),可以在if或else代码块中嵌套另一个if-else。
代码示例:嵌套if-else(登录验证逻辑)
/**
* 测试嵌套if-else:登录验证(先判断账号,再判断密码)
*/
export function testIfElseNested(): void {
console.log(`\n========== 嵌套if-else(授权登录验证) ==========`);
const isAuthorized: boolean = true; // 是否拥有登录授权(核心前置条件)
const username: string = "admin";
const password: string = "123456";
// 第一层:判断是否获得授权
if (isAuthorized === true) {
console.log("授权验证通过");
// 第二层:判断账号密码是否正确(嵌套层级≤3层)
if (username === "admin" && password === "123456") {
console.log("账号密码验证通过,登录成功!");
} else {
console.log("账号或密码错误,登录失败");
}
} else {
console.log("未获得授权");
}
}
运行效果
========== 嵌套if-else(授权登录验证) ==========
授权验证通过
账号密码验证通过,登录成功!
代码示例:if-else(布尔值隐式转换场景)
/**
* 测试if-else布尔值隐式转换:结合Boolean内置对象的空值判断
* 重点:展示非布尔值在条件语句中的隐式转换规则
*/
export function testIfElseNullCheck(): void {
console.log(`\n========== if-else(布尔值隐式转换) ==========`);
const username: string|null = "admin";
const password: string|null = null;
// 演示:非布尔值作为条件的隐式转换
if (username) {
console.log(`用户名:${username} → 非空值,隐式转换为true`);
} else {
console.log("用户名是空值,隐式转换为false");
}
if (password) {
console.log(`密码:${password} → 非空值,隐式转换为true`);
} else {
console.log(`密码:${password} → 空值,隐式转换为false`);
}
// 显式判断(推荐写法,规避隐式转换坑)
if (username !== "" && username !== null) {
console.log("显式判断:用户名非空且有效");
}
}
运行效果
========== if-else(布尔值隐式转换) ==========
用户名:admin → 非空值,隐式转换为true
密码:null → 空值,隐式转换为false
显式判断:用户名非空且有效
3.4 if-else易错点
- 条件表达式非布尔值(隐式转换坑):
- 非空字符串(如
"admin")、非0数字(如50)会隐式转为true,空字符串""、null、undefined、0会隐式转为false; - 错误示例:用
if (score)判断50分是否及格(50是非0数字→true,误判为及格),正确应写if (score >= 60); - 典型场景:
if (username)仅能判断是否为null/空字符串,但无法区分"0"/空格等无效值,需显式判断。
- 非空字符串(如
- 多条件顺序颠倒:多条件
if-else if必须按“范围从大到小”或“优先级从高到低”排序(如先判断90分以上,再判断80分以上),否则会出现逻辑错误; - 嵌套层级过多:超过3层嵌套会导致代码“臃肿”,后续可通过函数拆分优化;
- 遗漏边界条件:比如忘记判断
score === 60(刚好及格)、username === ""(空字符串),需覆盖所有可能的情况。
四、switch语句:多状态的等值判断
switch语句适用于多个等值条件判断(比如订单状态、性别、月份等),语法比多条件if-else更简洁,可读性更强。
4.0 全局枚举定义
// 定义订单状态枚举(全局作用域,语义化,避免魔法字符串)
enum OrderStatus {
Pending = "待支付",
Paid = "已支付",
Canceled = "已取消"
}
// 定义月份枚举(全局作用域,语义化命名,避免数字硬编码)
enum MonthEnum {
Jan = "1月",
Feb = "2月",
Mar = "3月"
}
4.1 基础语法
switch (判断值) {
case 值1:
// 判断值 === 值1 时执行
break; // 必须加break,否则会穿透到下一个case
case 值2:
// 判断值 === 值2 时执行
break;
case 值3:
// 判断值 === 值3 时执行
break;
default:
// 所有case都不匹配时执行(可选,建议保留)
break;
}
- 判断值类型:支持
number、string、enum(枚举)等基本类型,不支持对象; - 类型规范:判断值需显式标注类型(禁止隐式类型推断),且判断值类型需与case值类型严格一致(ArkTS 用
===严格相等判断); - 等值判断:使用
===严格相等(值和类型都必须匹配); break关键字:用于终止switch语句,避免“穿透效应”(即执行完当前case后,继续执行下一个case);default分支:用于处理所有case之外的异常情况,提升代码健壮性。
代码示例:基础switch(订单状态处理)
/**
* 测试基础switch:订单状态处理(多等值条件)
*/
export function testSwitchBasic(): void {
console.log(`\n========== 基础switch(订单状态处理) ==========`);
const orderStatus: string = "Paid";
switch (orderStatus) {
case "Pending":
console.log("订单状态:待支付,提示用户尽快完成支付");
break; // 终止当前case,避免穿透
case "Paid":
console.log("订单状态:已支付,系统将在24小时内发货");
break;
case "Canceled":
console.log("订单状态:已取消,可重新下单");
break;
default:
console.log("订单状态:未知,建议联系客服核实");
break;
}
}
运行效果
========== 基础switch(订单状态处理) ==========
订单状态:已支付,系统将在24小时内发货
4.2 switch的穿透效应(fallthrough)
当case中没有break时,会触发“穿透效应”——执行完当前case后,继续执行下一个case的代码,直到遇到break或switch结束。
提示:穿透不是bug,而是特性,适用于“多个case共享同一逻辑”的场景。
代码示例:穿透效应(月份季节判断)
/**
* 测试switch穿透效应:月份对应季节(多个case对应同一逻辑)
*/
export function testSwitchFallthrough(): void {
console.log(`\n========== switch穿透效应(月份季节判断) ==========`);
// 推荐显式标注类型:避免隐式推断导致case值类型不匹配
const month: number = 3;
switch (month) {
// 12/1/2月都属于冬季(穿透共享逻辑)
case 12:
case 1:
case 2:
console.log(`月份:${month},季节:冬季`);
break;
// 3/4/5月都属于春季
case 3:
case 4:
case 5:
console.log(`月份:${month},季节:春季`);
break;
// 6/7/8月都属于夏季
case 6:
case 7:
case 8:
console.log(`月份:${month},季节:夏季`);
break;
// 9/10/11月都属于秋季
case 9:
case 10:
case 11:
console.log(`月份:${month},季节:秋季`);
break;
default:
console.log(`月份:${month},无效月份`);
break;
}
}
运行效果
========== switch穿透效应(月份季节判断) ==========
月份:3,季节:春季
4.3 switch与枚举结合(最佳实践)
代码示例:switch+枚举(订单状态优化)
/**
* 测试switch+枚举:订单状态处理(最佳实践)
*/
export function testSwitchWithEnum_Order(currentStatus: OrderStatus): void {
console.log(`\n========== switch+枚举(订单状态优化) ==========`);
switch (currentStatus) {
case OrderStatus.Pending:
console.log(`订单状态:${currentStatus},提示用户尽快完成支付`);
break;
case OrderStatus.Paid:
console.log(`订单状态:${currentStatus},系统将在24小时内发货`);
break;
case OrderStatus.Canceled:
console.log(`订单状态:${currentStatus},可重新下单`);
break;
default:
console.log(`订单状态:未知,建议联系客服核实`);
break;
}
}
运行效果
========== switch+枚举(订单状态优化) ==========
订单状态:待支付,提示用户尽快完成支付
代码示例2:switch+枚举(月份场景,优化穿透效应)
/**
* 测试switch+枚举:月份判断(穿透效应+枚举最佳实践)
*/
export function testSwitchWithEnum_Month(currentMonth: MonthEnum): void {
console.log(`\n========== switch+枚举(月份判断) ==========`);
switch (currentMonth) {
// 1月/2月共享冬季逻辑(利用穿透效应简化代码)
case MonthEnum.Jan:
case MonthEnum.Feb:
console.log(`当前月份:${currentMonth},属于冬季`);
break;
case MonthEnum.Mar:
console.log(`当前月份:${currentMonth},属于春季`);
break;
default:
console.log(`当前月份:${currentMonth},无效月份`);
break;
}
}
运行效果
========== switch+枚举(月份判断) ==========
当前月份:2月,属于冬季
4.4 switch易错点
- 遗漏break:这是最常见错误,会导致穿透效应,除非主动需要穿透,否则每个case都必须加
break; - 使用非等值条件:switch只能判断“是否相等”,不能判断范围(比如
score >= 90),范围判断需用if-else; - 判断值类型不匹配:比如
switch (123)和case "123",因类型不同不会匹配,会执行default; - 忽略default分支:建议始终保留default,处理异常情况(比如用户输入无效值);
- 枚举作用域错误:枚举定义在函数内会导致外部调用时“未定义”,需定义在全局作用域;
- 隐式类型推断:判断值未显式标注类型(如
const month = 3;),易导致与case值类型不匹配。
五、三元运算符:二选一的简洁写法
三元运算符是if-else的简写形式,仅适用于“二选一”的简单逻辑,语法简洁,一行代码即可完成判断。
5.1 基础语法
条件表达式 ? 条件为true时的返回值 : 条件为false时的返回值
- 条件表达式必须返回
boolean类型; - 返回值可以是任意类型(数字、字符串、变量、甚至函数调用);
- 优先级较低,复杂场景建议用括号包裹(比如结合其他运算符时)。
代码示例:基础三元运算符(简单二选一)
/**
* 测试基础三元运算符:简单二选一逻辑
*/
export function testTernaryBasic(): void {
console.log(`\n========== 基础三元运算符(简单二选一) ==========`);
// 场景1:判断年龄是否成年
const age: number = 20; // 显式标注数字类型
const adultStatus: string = age >= 18 ? "成年" : "未成年"; // 显式标注字符串类型
console.log(`年龄:${age},状态:${adultStatus}`);
// 场景2:判断商品是否库存充足
const stock: number = 5; // 显式标注数字类型
const stockStatus: string = stock > 0 ? "库存充足" : "已售罄"; // 显式标注字符串类型
console.log(`商品库存:${stock},状态:${stockStatus}`);
// 场景3:结合函数调用
const score: number = 75; // 显式标注数字类型
// 显式标注字符串类型
const result: string = score >= 60 ? "恭喜,考试及格!" : "很遗憾,考试不及格,请再接再厉!";
console.log(`分数:${score},结果:${result}`);
}
运行效果
========== 基础三元运算符(简单二选一) ==========
年龄:20,状态:成年
商品库存:5,状态:库存充足
分数:75,结果:恭喜,考试及格!
5.2 统一测试函数
/**
* 统一调用所有测试函数
*/
export function allTest(): void {
testIfElseBasic(); // 基础if-else
testIfElseMulti(); // 多条件if-else if-else
testIfElseNested(); // 嵌套if-else
testIfElseNullCheck(); // 布尔值隐式转换
testSwitchBasic(); // 基础switch
testSwitchFallthrough(); // switch穿透效应
testSwitchWithEnum_Order(OrderStatus.Pending); // switch+枚举(订单)
testSwitchWithEnum_Month(MonthEnum.Feb); // switch+枚举(月份)
testTernaryBasic(); // 三元运算符
}
5.3 三元运算符的限制与注意事项
- 仅支持二选一:不能处理多条件逻辑(比如成绩等级判断),否则代码会变得冗长且可读性差;
- 避免嵌套使用:嵌套三元运算符(比如
a ? b : c ? d : e)会让代码难以理解,建议用if-else替代; - 复杂逻辑慎用:当返回值或条件表达式复杂时(比如多行代码),优先用if-else,保证可读性。
错误示例:嵌套三元运算符(不推荐)
// 不推荐:嵌套三元运算符,可读性差
const score: number = 85; // 显式标注数字类型
const level: string = score >= 90 ? "A" : score >= 80 ? "B" : score >= 60 ? "C" : "D"; // 显式标注字符串类型
console.log(`等级:${level}`); // 输出:B,但代码难以快速理解
六、分支语句适用场景与特性对比
| 语句类型 | 核心适用场景 | 核心优势 | 核心限制 | 典型业务场景 |
|---|---|---|---|---|
if-else |
复杂条件、范围判断、嵌套逻辑 | 灵活适配任意布尔条件判断 | 多条件场景代码易冗长 | 成绩等级判断、登录验证、权限控制 |
switch |
多等值条件、状态类判断 | 语法简洁、可读性强,适配枚举 | 仅支持等值判断,需手动加break | 订单状态处理、月份季节判断、枚举匹配 |
| 三元运算符 | 简单二选一逻辑 | 一行代码完成,极简高效 | 不支持多条件,嵌套可读性极差 | 成年判断、库存状态、简单结果返回 |
七、核心总结
ArkTS分支语句的核心价值是“按条件精准执行差异化逻辑”,掌握其使用的关键在于精准选型+规范落地,而非单纯记忆语法:
1. 选型逻辑:贴合场景而非堆砌语法
基于条件特征选择对应语句,核心原则是“简单场景用简洁语法,复杂场景用灵活语法”:
- 二选一的极简逻辑(如“是否成年”“库存是否充足”):优先用三元运算符,减少代码冗余;
- 多值等值判断(如“订单状态”“月份匹配”):优先用switch(结合枚举可规避魔法字符串/数字,提升可维护性);
- 范围/嵌套/复杂条件(如“成绩等级分层”“登录多维度验证”):用if-else,兼顾灵活性与逻辑完整性。
2. 规范落地:规避高频错误
- 类型安全:条件表达式必须为布尔值,变量显式标注类型(number/string/enum等),杜绝隐式类型转换错误;
- 语法约束:switch需为非穿透case添加
break、保留default分支处理异常;if-else嵌套层级控制在3层内,避免逻辑混乱; - 边界覆盖:条件判断需考虑临界值(如60分及格线),枚举需定义在全局作用域,避免调用时“未定义”错误。
3. 核心原则:可读性>简洁性
无论选择哪种分支语句,最终都以“逻辑清晰、异常覆盖、易于维护”为核心——比如避免嵌套三元运算符(即便代码更短,也会大幅降低可读性),switch遗漏break(易触发非预期的穿透效应),这些看似“小问题”,却是编写ArkTS代码时最易踩的坑,也是影响代码可维护性的关键。
八、开始测试
// pages/Index.ets
import { allTest } from '../utils/FlowControlTest';
@Entry
@Component
struct Index {
aboutToAppear(): void {
allTest();
}
build() {
Column() {
Text("流程控制(上)——分支语句")
.fontSize(30)
.fontWeight(FontWeight.Bold)
Text("运行日志请查看控制台")
.fontSize(16)
.margin(20)
.fontColor(Color.Grey)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center);
}
}
九、代码仓库
- 工程名称:FlowControlBranchDemo
- 仓库地址:https://gitee.com/juhetianxia321/harmony-os-code-base.git
十、下节预告
下一节我们将进入流程控制(下)——循环语句的学习,这是流程控制的另一核心内容,也是处理批量数据、重复逻辑的关键,重点包括:
- 掌握
for循环的核心语法与场景(固定次数循环,如数组遍历、数字遍历),理解循环计数器的执行逻辑 - 掌握
for...of循环的简洁遍历方式,学会处理数组、字符串等可迭代对象(含索引获取技巧) - 掌握
while和do-while循环的用法,区分“先判断后执行”与“先执行后判断”的差异,学会预防死循环 - 学会使用
break和continue关键字控制循环流程,优化循环执行效率(如提前终止、过滤无效迭代)
浙公网安备 33010602011771号