ArkTS基础第三节:流程控制
炼气三重天
【学习目标】
- 掌握
if-else(分支)、switch-case(固定值匹配)的语法与场景差异,能处理嵌套逻辑 - 明确
for(已知次数)、for...of(简洁遍历)、while/do-while(条件驱动)的核心用法,能按需选择循环 - 熟练使用
break(终止循环)、continue(跳过当前轮)控制流程,理解标签跳出多层循环 - 掌握安全无限循环的写法,规避“死循环”风险,理解循环嵌套逻辑
- 强化类型安全意识,能通过输入校验避免循环/判断中的类型错误
- 独立完成猜数字、杨辉三角、99乘法表等实战案例,提升逻辑思维
【学习重点】
- 条件判断:
if-else(范围/复杂条件)、switch-case(离散值)的场景选择,break防穿透 - 循环结构:
for(需索引)、for...of(仅遍历元素)、while(未知次数)、do-while(至少执行一次) - 流程控制:
break(终止整个循环)、continue(跳过当前轮)的差异,标签跳出多层循环 - 安全实践:无限循环必须有终止条件、循环变量显式声明类型、输入先校验再使用
- 实战案例:猜数字(循环+条件判断)、杨辉三角(嵌套循环)、99乘法表(嵌套循环+格式化)
一、新建工程项目
- 项目名:
FlowControlDemo - 核心文件结构(仅列当前章节需新增/修改的文件):
ets/
├── pages/
│ └── Index.ets(复用基础结构,更新标题和知识点提示)
└── utils/└── TestFlowControl.ets(新增,存放流程控制测试函数)
1.1 核心文件说明
Index.ets:复用第二节基础UI结构,仅需更新页面标题和核心知识点提示(完整代码见附录);TestFlowControl.ets:新增测试工具类,所有流程控制相关测试函数集中在此,通过create指令完成文件的新建与代码写入。
1.2 新建测试工具类 TestFlowControl.ets
// utils/TestFlowControl.ets
/*** 流程控制测试工具类* 编码规范:一行一个变量、显式声明类型、注释清晰*/
export class TestFlowControl {// 所有测试函数按知识点顺序添加在此(下方依次展开)/*** 统一执行所有测试(固定入口,放在类末尾)*/static runAllTests() {console.log("\n===== 第三节:流程控制测试开始 =====");TestFlowControl.testIfElse();TestFlowControl.testSwitchCase();TestFlowControl.testForLoop();TestFlowControl.testForOfLoop();TestFlowControl.testWhileLoop();TestFlowControl.testInfiniteLoop();TestFlowControl.testNestedLoop();TestFlowControl.testBreakContinue();TestFlowControl.testTypeSafety();TestFlowControl.testGuessNumber();TestFlowControl.testYanghuiTriangle();TestFlowControl.testMultiplicationTable();console.log("===== 第三节:流程控制测试结束 =====");}
}
补充:日志过滤技巧(实用工具)
由于多个测试函数会输出日志,可通过以下方式快速定位结果:
- 测试日志前加「模块标签」(如
[testIfElse]); - Log面板搜索标签即可过滤无关日志,提升调试效率。
二、条件判断:让程序学会“做决策”
2.1 if-else系列(单分支/双分支/多分支/嵌套)
核心用于范围判断、复杂条件组合,支持嵌套逻辑:
/*** if-else系列:单分支、双分支、多分支、嵌套* 核心:范围判断、复杂条件组合用if-else*/
static testIfElse() {console.log("\n===== if-else系列测试 =====");// 1. 单分支if:满足条件才执行let score: number = 85;if (score >= 60) {console.log(`[testIfElse] if单分支:分数${score},考试及格`);}// 2. 双分支if-else:覆盖两种对立情况let age: number = 17;if (age >= 18) {// 满足执行console.log(`[testIfElse] if-else双分支:${age}岁,已成年,可独立购票`);} else {// 不满足执行console.log(`[testIfElse] if-else双分支:${age}岁,未成年,需成人陪同`);}// 3. 多分支if-else if-else:递进条件判断let mathScore: number = 88;if (mathScore >= 90) {console.log(`[testIfElse] if-else多分支:${mathScore}分,评级优秀`);} else if (mathScore >= 80) {console.log(`[testIfElse] if-else多分支:${mathScore}分,评级良好`);} else if (mathScore >= 60) {console.log(`[testIfElse] if-else多分支:${mathScore}分,评级及格`);} else {console.log(`[testIfElse] if-else多分支:${mathScore}分,评级不及格`);}// 4. 嵌套if:内层条件依赖外层结果let isStudent: boolean = true;if (score >= 60) {console.log("[testIfElse] 嵌套if:考试通过");if (score >= 90 && isStudent) {console.log("[testIfElse] 嵌套if:满足奖学金条件,发放奖学金");} else {console.log("[testIfElse] 嵌套if:未达到奖学金条件");}} else {console.log("[testIfElse] 嵌套if:考试未通过,需补考");}// 避坑点:不同类型先转换再判断let inputScore: string = "92";let realScore: number = Number(inputScore);if (realScore >= 90) {console.log(`[testIfElse] 避坑示例:输入${inputScore}转换后为${realScore},评级优秀`);}
}
2.2 switch-case(固定值匹配)
核心用于离散固定值匹配,必须加break防穿透,default处理无效值:
/*** switch-case:固定离散值匹配* 核心:必须加break防穿透,default处理无效值*/
static testSwitchCase() {console.log("\n===== switch-case测试 =====");// 1. 基础用法:匹配星期let week: number = 3;switch (week) {case 1:console.log("[testSwitchCase] switch-case:周一,开启工作模式");break;case 2:console.log("[testSwitchCase] switch-case:周二,处理日常任务");break;case 3:console.log("[testSwitchCase] switch-case:周三,进度复盘");break;case 4:console.log("[testSwitchCase] switch-case:周四,准备周报");break;case 5:console.log("[testSwitchCase] switch-case:周五,总结本周");break;default:console.log("[testSwitchCase] switch-case:无效日期,请输入1-5");}// 2. 避坑重点:遗漏break导致穿透(反例)console.log("\n===== switch-case穿透示例(无break)=====");let num: number = 2;switch (num) {case 2:console.log("[testSwitchCase] case 2 执行(无break)");case 3:console.log("[testSwitchCase] case 3 被穿透执行(错误!)");case 4:console.log("[testSwitchCase] case 4 继续穿透(错误!)");break;}console.log("[testSwitchCase] 修复方案:每个独立case后必须添加break");// 3. 实战场景:匹配用户角色(字符串类型)let role: string = "vip";switch (role) {case "admin":console.log("[testSwitchCase] 用户角色:管理员,拥有全部权限");break;case "vip":console.log("[testSwitchCase] 用户角色:VIP,拥有会员专属权限");break;case "user":console.log("[testSwitchCase] 用户角色:普通用户,拥有基础权限");break;default:console.log("[testSwitchCase] 用户角色:游客,仅可查看公开内容");}// 4. 特殊用法:多个值匹配同一逻辑(合理穿透)let season: string = "12";switch (season) {case "12":case "1":case "2":console.log(`[testSwitchCase] 季节匹配:${season}月,属于冬季`);break;default:console.log(`[testSwitchCase] 季节匹配:${season}月,属于其他季节`);}
}
三、循环结构:让程序学会“重复做”
3.1 for循环(已知次数、需要索引)
语法:for (初始化; 条件; 更新),适用于已知次数、需要索引的场景:
/*** for循环:已知次数、需要索引的场景* 核心:控制精确,支持复杂迭代和嵌套*/
static testForLoop() {console.log("\n===== for循环测试 =====");// 1. 基础用法:计算1-10的和let sum: number = 0;for (let i: number = 1; i <= 10; i++) {sum += i;console.log(`[testForLoop] for循环:i=${i},当前和=${sum}`);}console.log(`[testForLoop] for循环结果:1-10的和=${sum}`);// 2. 遍历数组(带索引)let fruits: string[] = ["苹果", "香蕉", "橙子", "葡萄"];console.log("\n[testForLoop] for循环遍历数组(带索引):");for (let i: number = 0; i < fruits.length; i++) {console.log(`[testForLoop] 索引${i}:${fruits[i]}`);}// 3. 嵌套for循环:打印3行4列星号console.log("\n[testForLoop] 嵌套for循环:3行4列星号");for (let row: number = 1; row <= 3; row++) { // 外层:控制行数(3行)let line: string = "";for (let col: number = 1; col <= 4; col++) { // 内层:控制列数(每行4个)line += "* ";}console.log("[testForLoop] " + line);}// 避坑点:循环变量显式声明类型console.log("\n[testForLoop] 避坑示例:循环变量显式声明number类型");for (let j: number = 5; j > 0; j--) {console.log(`[testForLoop] j=${j}`);}
}
3.2 for...of循环(简洁遍历元素,无需索引)
直接遍历元素,无需维护索引,配合break/continue更灵活:
/*** for...of循环:简洁遍历元素,无需索引* 核心:数组/字符串遍历,仅需元素值时优先用*/
static testForOfLoop() {console.log("\n===== for...of循环测试 =====");let fruits: string[] = ["苹果", "香蕉", "橙子", "葡萄"];// 1. 基础用法:直接遍历元素console.log("[testForOfLoop] for...of基础遍历(仅元素):");for (let fruit of fruits) {console.log(`[testForOfLoop] 当前水果:${fruit}`);}// 2. 配合break:找到目标元素后终止let targetFruit: string = "橙子";console.log(`\n[testForOfLoop] for...of+break:查找目标水果"${targetFruit}"`);for (let fruit of fruits) {if (fruit === targetFruit) {console.log(`[testForOfLoop] 找到目标:${fruit},终止循环`);break;}console.log(`[testForOfLoop] 遍历中:${fruit}(非目标)`);}// 3. 配合continue:跳过特定元素console.log("\n[testForOfLoop] for...of+continue:跳过\"香蕉\"");for (let fruit of fruits) {if (fruit === "香蕉") {console.log(`[testForOfLoop] 跳过元素:${fruit}`);continue;}console.log(`[testForOfLoop] 保留元素:${fruit}`);}// 4. 遍历entries:同时获取索引和元素console.log("\n[testForOfLoop] for...of遍历entries(索引+元素):");for (let entry of fruits.entries()) {console.log(`[testForOfLoop] 索引${entry[0]}:${entry[1]}`);}// 5. 遍历字符串let str: string = "ArkTS";console.log("\n[testForOfLoop] for...of遍历字符串(逐个字符):");for (let char of str) {console.log(`[testForOfLoop] 字符:${char}`);}
}
3.3 while/do-while循环(条件驱动,未知次数)
while:先判断后执行,条件不满足则一次不执行do-while:先执行一次,再判断条件,至少执行一次
/*** while/do-while循环:条件驱动,未知次数* 核心:while先判断后执行,do-while至少执行一次*/
static testWhileLoop() {console.log("\n===== while/do-while循环测试 =====");// 1. while循环:累加至和超过100let total: number = 0;let num: number = 1;console.log("[testWhileLoop] while循环:累加至和超过100");while (total <= 100) {total += num;console.log(`[testWhileLoop] 累加第${num}个数,当前和=${total}`);num++;}console.log(`[testWhileLoop] while循环结束:最终和=${total}`);// 2. do-while循环:至少执行一次console.log("\n[testWhileLoop] do-while循环:至少执行一次");let inputNum: number = 0;do {inputNum = Math.floor(Math.random() * 10);console.log(`[testWhileLoop] 生成随机数:${inputNum}`);} while (inputNum < 5);console.log(`[testWhileLoop] do-while循环结束:最终随机数=${inputNum}`);// 3. 实战场景:模拟用户登录校验console.log("\n[testWhileLoop] do-while实战:用户登录校验");let userInput: string = "";do {userInput = "admin123";console.log(`[testWhileLoop] 模拟用户输入密码:${userInput}`);} while (userInput !== "admin123");console.log("[testWhileLoop] 登录成功!密码正确");// 避坑点:确保循环条件能终止console.log("\n[testWhileLoop] 避坑示例:while循环条件必须可终止");let count: number = 0;while (count < 3) {console.log(`[testWhileLoop] 安全循环:count=${count}`);count++;}
}
3.4 安全无限循环(while(true))
仅用于“不确定结束时间”的场景,必须通过break明确终止条件:
/*** 安全无限循环:while(true) + break终止* 核心:必须有明确终止条件,禁止无break的死循环*/
static testInfiniteLoop() {console.log("\n===== 安全无限循环测试 =====");// 场景1:固定次数后终止let loopCount: number = 0;const maxCount: number = 5;console.log(`[testInfiniteLoop] 无限循环:最多执行${maxCount}次`);while (true) {loopCount++;console.log(`[testInfiniteLoop] 循环执行次数:${loopCount}`);if (loopCount >= maxCount) {console.log(`[testInfiniteLoop] 达到最大次数${maxCount},终止循环`);break;}}// 场景2:模拟事件监听console.log("\n[testInfiniteLoop] 无限循环实战:模拟订单支付监听");let isPaid: boolean = false;let listenCount: number = 0;while (true) {listenCount++;console.log(`[testInfiniteLoop] 监听订单支付状态(第${listenCount}次)`);if (listenCount === 3) {isPaid = true;console.log("[testInfiniteLoop] 订单已支付!");}if (isPaid) {console.log("[testInfiniteLoop] 支付成功,终止监听");break;}}// 危险示例:无终止条件的死循环(禁止使用)console.log("\n[testInfiniteLoop] ⚠️ 危险示例:无终止条件的死循环(已注释)");console.log("[testInfiniteLoop] 安全原则:while(true)必须搭配break,且有明确终止条件");
}
3.5 嵌套循环(多维数据处理)
外层控制整体结构,内层控制局部细节,多用于二维数组、图形绘制等场景:
/*** 嵌套循环:外层控制结构,内层控制细节* 核心:多维数据处理,嵌套层级≤3层*/
static testNestedLoop() {console.log("\n===== 嵌套循环测试 =====");// 场景1:遍历二维数组let matrix: number[][] = [[1, 2], [3, 4], [5, 6]];console.log("[testNestedLoop] 嵌套循环:遍历二维数组(行×列)");for (let i: number = 0; i < matrix.length; i++) { // 外层:控制行数let rowData: number[] = matrix[i];for (let j: number = 0; j < rowData.length; j++) { // 内层:控制列数console.log(`[testNestedLoop] 行${i+1}列${j+1}:${rowData[j]}`);}}// 场景2:打印5行等腰直角三角形console.log("\n[testNestedLoop] 嵌套循环:打印5行等腰直角三角形");for (let i: number = 1; i <= 5; i++) { // 外层:控制行数(5行)let line: string = "";for (let j: number = 1; j <= i; j++) { // 内层:控制每行星号数(等于行数)line += "* ";}console.log("[testNestedLoop] " + line);}// 场景3:计算二维数组所有元素的和let totalSum: number = 0;console.log("\n[testNestedLoop] 嵌套循环:计算二维数组所有元素的和");for (let row of matrix) { // 外层:遍历每行for (let num of row) { // 内层:遍历每行元素totalSum += num;}}console.log(`[testNestedLoop] 二维数组所有元素的和:${totalSum}`);// 避坑提示:嵌套层级≤3层console.log("\n[testNestedLoop] 避坑提示:嵌套循环层级≤3层,避免性能问题");
}
四、流程控制:break与continue(掌控循环节奏)
break:终止整个循环(多层循环可用标签跳出外层)continue:跳过当前轮次,直接进入下一轮
/*** break与continue:控制循环流程* 核心:break终止整个循环,continue跳过当前轮*/
static testBreakContinue() {console.log("\n===== break与continue测试 =====");// 1. break:终止整个循环(单层)let nums: number[] = [3, 5, 4, 7, 8, 9];console.log("[testBreakContinue] break示例:查找第一个偶数,找到后终止");for (let n of nums) {if (n % 2 === 0) {console.log(`[testBreakContinue] 找到第一个偶数:${n},终止循环`);break;}console.log(`[testBreakContinue] 当前元素(奇数):${n}`);}// 2. continue:跳过当前轮次(单层)console.log("\n[testBreakContinue] continue示例:累加1-10的奇数和,跳过偶数");let sumOdd: number = 0;for (let i: number = 1; i <= 10; i++) {if (i % 2 === 0) {console.log(`[testBreakContinue] 跳过偶数:${i}`);continue;}sumOdd += i;console.log(`[testBreakContinue] 当前奇数:${i},累计和:${sumOdd}`);}console.log(`[testBreakContinue] 1-10的奇数和:${sumOdd}`);// 3. 多层循环+标签:break跳出外层console.log("\n[testBreakContinue] 多层循环+标签:break跳出外层循环");outerLoop: for (let i: number = 1; i <= 3; i++) { // 外层循环标签:outerLoopfor (let j: number = 1; j <= 3; j++) { // 内层循环if (i === 2 && j === 2) {console.log(`[testBreakContinue] i=${i}, j=${j},触发break outerLoop,跳出外层循环`);break outerLoop;}console.log(`[testBreakContinue] i=${i}, j=${j}`);}}// 4. 多层循环+continue:仅跳过当前内层轮次console.log("\n[testBreakContinue] 多层循环+continue:仅跳过当前内层循环");for (let i: number = 1; i <= 3; i++) { // 外层循环for (let j: number = 1; j <= 3; j++) { // 内层循环if (j === 2) {console.log(`[testBreakContinue] i=${i}, j=${j},触发continue,跳过当前内层轮次`);continue;}console.log(`[testBreakContinue] i=${i}, j=${j}`);}}
}
五、类型安全与常见错误规避
核心原则:显式声明类型、输入先校验、避免不同类型比较、循环条件可终止:
/*** 类型安全与常见错误规避* 核心:显式声明类型、输入先校验、避免死循环*/
static testTypeSafety() {console.log("\n===== 类型安全与常见错误测试 =====");// 正确示例1:循环变量显式声明类型console.log("[testTypeSafety] 正确示例:循环变量显式声明number类型");for (let i: number = 0; i < 5; i++) {console.log(`[testTypeSafety] i=${i}(类型:${typeof i})`);}// 错误1:循环变量类型错误(编译报错)console.log("\n[testTypeSafety] 错误1:循环变量类型错误(string vs number)");// for (let k: string = "0"; k < 5; k++) { // 编译报错:Type 'string' is not comparable to type 'number'// console.log(k);// }console.log("[testTypeSafety] 修复方案:循环变量类型与条件比较类型一致(均为number)");// 错误2:输入未转类型直接比较console.log("\n[testTypeSafety] 错误2:输入未转类型,直接比较");let inputAge: string = "18";let realAge: number = Number(inputAge);if (realAge >= 18) {console.log(`[testTypeSafety] 修复后:输入${inputAge}转number为${realAge},已成年`);}// 错误3:switch-case遗漏break导致穿透console.log("\n[testTypeSafety] 错误3:switch-case遗漏break");let type: number = 2;switch (type) {case 2:console.log("[testTypeSafety] case 2 执行");case 3:console.log("[testTypeSafety] case 3 被穿透执行(错误)");break;}console.log("[testTypeSafety] 修复方案:每个独立case后添加break");// 错误4:死循环(条件永远为true)console.log("\n[testTypeSafety] 错误4:死循环(条件永远为true)");// let deadCount: number = 0;// while (true) { // 编译不报错,但运行时无限循环// deadCount++;// }console.log("[testTypeSafety] 修复方案:确保循环条件能在某个时刻变为false");// 正确示例2:输入校验(类型+范围)console.log("\n[testTypeSafety] 正确示例:输入校验(类型+范围)");let inputScore: string | null = "95";let score: number = inputScore ? Number(inputScore) : 0;if (!isNaN(score) && score >= 0 && score <= 100) {console.log(`[testTypeSafety] 输入有效:分数${score}分`);} else {console.log("[testTypeSafety] 输入无效,请输入0-100的数字");}
}
六、实战案例:综合运用流程控制
6.1 实战案例1:猜数字游戏(输入猜测数字:循环+条件判断+输入校验)请在附录查看
6.2 实战案例2:杨辉三角(嵌套循环+二维数组)
/*** 实战案例2:杨辉三角(默认10行)* 核心思路:* 1. 初始化二维数组:用外层循环控制行数,每行是一个独立数组;* 2. 填充每行元素:首尾元素固定为1,中间元素 = 上一行相邻两个元素之和;* 3. 格式化输出:通过空格填充实现居中,提升可读性。* 规则:每行首尾为1,中间元素=上一行相邻两元素之和* ✨ 扩展需求:支持用户输入行数(1-20),输入非法时默认显示10行;添加每行元素的逗号分隔格式。*/
static testYanghuiTriangle(rowCount: number = 10) {// 补充输入校验:限制1-20行,非法值默认10行if (isNaN(rowCount) || rowCount < 1 || rowCount > 20) {rowCount = 10;console.log("[testYanghuiTriangle] 输入行数非法,默认显示10行");}console.log(`\n===== 实战案例2:杨辉三角(${rowCount}行) =====`);let triangle: number[][] = [];for (let rowIdx: number = 0; rowIdx < rowCount; rowIdx++) { // 外层:控制行数let currentRow: number[] = [];for (let colIdx: number = 0; colIdx <= rowIdx; colIdx++) { // 内层:控制每行元素数if (colIdx === 0 || colIdx === rowIdx) {currentRow.push(1); // 首尾元素固定为1} else {const prevRow: number[] = triangle[rowIdx - 1];// 核心:中间元素 = 上一行相邻两元素之和currentRow.push(prevRow[colIdx - 1] + prevRow[colIdx]);}}triangle.push(currentRow);}// 格式化居中输出triangle.forEach((row: number[], index: number) => {const spaceCount: number = (rowCount - index - 1) * 2;const rowStr: string = row.join(' ');console.log(' '.repeat(spaceCount) + rowStr);});
}
6.3 实战案例3:99乘法表(嵌套循环+格式化)
/*** 实战案例3:99乘法表(直角版+带边框版)* 核心思路:* 1. 直角版:外层循环控制乘数(1-9),内层循环控制被乘数(1-当前乘数),拼接算式字符串;* 2. 带边框版:先定义边框格式,外层循环控制乘数,内层循环拼接带对齐的算式,首尾加边框字符。* ✨ 扩展需求:打印“倒三角版99乘法表”(第1行9个算式,第2行8个,...,第9行1个),可通过调整循环变量的起始与终止值实现。*/
static testMultiplicationTable() {console.log("\n===== 实战案例3:99乘法表 =====");// 版本1:直角三角形版console.log("[testMultiplicationTable] 【直角三角形版】");for (let i: number = 1; i <= 9; i++) { // 外层:控制乘数(1-9)let line: string = "";for (let j: number = 1; j <= i; j++) { // 内层:控制被乘数(1-当前乘数)line += `${j}×${i}=${j*i}\t`;}console.log("[testMultiplicationTable] " + line);}// 版本2:带边框矩形版console.log("\n[testMultiplicationTable] 【带边框矩形版】");const border: string = "+--------".repeat(9) + "+";console.log(border);for (let i: number = 1; i <= 9; i++) { // 外层:控制乘数(1-9)let line: string = "|";for (let j: number = 1; j <= 9; j++) { // 内层:控制被乘数(1-9)const content: string = `${j}×${i}=${j*i}`;line += content.padEnd(7) + "|";}console.log(line);console.log(border);}
}
核心语法速查表
| 应用场景 | 推荐语法 | 关键注意点 |
|---|---|---|
| 范围判断、复杂条件组合 | if-else/if-else if | 嵌套层级≤2层,不同类型先转类型再判断 |
| 离散固定值匹配(如角色、星期) | switch-case | 必须加 break 防穿透,用 default 处理无效值 |
| 已知次数、需要索引 | for 循环 | 循环变量显式声明 number 类型 |
| 仅遍历元素、无需索引 | for...of | 配合 break/continue 优化性能 |
| 未知次数、条件驱动 | while 循环 | 确保条件能终止,避免死循环 |
| 至少执行一次(如输入校验) | do-while | 适合“先执行再判断”的场景(如登录校验) |
| 不确定结束时间(如事件监听) | while(true)+break | 必须有明确的终止条件(如支付成功) |
【课堂小结】
- 条件判断选型:
- 范围/复杂条件 →
if-else;离散固定值 →switch-case(加break防穿透)
- 范围/复杂条件 →
- 循环选型:
- 已知次数/需索引 →
for;仅遍历元素 →for...of;未知次数 →while;至少执行一次 →do-while - 不确定结束时间 → 安全无限循环(
while(true)+break)
- 已知次数/需索引 →
- 流程控制核心:
break终止整个循环,continue跳过当前轮;多层循环用标签跳出外层
- 避坑重点:
- 类型安全:显式声明类型,输入先转类型再使用
- 循环安全:无限循环必须有
break,嵌套层级≤3层
【课后练习】(基础必做)
- 操作题:添加
testLeapYear方法,判断year=2024是否为闰年(能被4整除且不被100整除,或能被400整除)。 - 操作题:添加
testSumDivisibleBy3方法,用for循环计算1-100中能被3整除的数字之和。 - 操作题:添加
testIsoscelesTriangle方法,用嵌套for循环打印7行等腰三角形(星号数:1、3、5、7、5、3、1)。
✨ 提示:前4行星号数=2×行号-1(递增),后3行星号数=13-2×行号(递减),用空格填充实现居中。 - 分析题:添加
testLoopAnalysis方法,执行let a=2; let b=0; for(let i=0; i<3; i++){ b += ++a; },打印a和b并解释过程。 - 操作题:添加
testFindMaxIn2DArray方法,找出二维数组[[1,5,3],[9,2,7],[4,6,8]]的最大值及行号、列号。
✨ 提示:用嵌套循环遍历每个元素,用变量记录“当前最大值+对应的行/列索引”,遍历中更新。 - 改错题:添加
testFixLoopError方法,修复以下代码并说明错误原因:let num: string = "5"; // 错误1 while (num < 10) { // 错误2console.log(num);num++; // 错误3 } - 操作题:实现99乘法表的倒三角版(第1行9个算式,第2行8个...第9行1个)
✨ 提示:外层循环i从9到1递减,内层循环j从1到i递增,保持算式格式一致。
【代码仓库】
第三节项目代码(FlowControlDemo)已同步:https://gitee.com/juhetianxia321/harmony-os-code-base.git
【下节预告】
第四节将进入核心内置对象与高级集合章节,系统学习 Number(数值处理)、String(字符串操作)、Array(数组增删改查)的核心;掌握 Map 键值对集合的存储与遍历逻辑,以及 Set 集合的自动去重特性与实战用法;结合案例实现 字符串格式化 数组去重 学生成绩映射存储 等实用功能,让你能高效处理各类数据,为复杂应用开发夯实数据操作基础。
七、鸿蒙开发者学习与认证指引
(一)、官方学习班级报名(免费)
- 班级链接:HarmonyOS赋能资源丰富度建设(第四期)
- 学号填写规则:填写个人手机号码即可完成班级信息登记
(二)、HarmonyOS应用开发者认证考试(免费)
-
考试链接:HarmonyOS开发者能力认证入口
-
认证等级及适配人群
- 基础认证:适配软件工程师、移动应用开发人员,需掌握HarmonyOS基础概念、DevEco Studio基础使用、ArkTS及ArkUI基础开发等能力;
- 高级认证:适配项目经理、工程架构师,需掌握系统核心技术理念、应用架构设计、关键技术开发及应用上架运维等能力;
- 专家认证:适配研发经理、解决方案专家,需掌握分布式技术原理、端云一体化开发、跨端迁移及性能优化等高级能力。
-
认证权益:通过认证可获得电子版证书以及其他专属权益。
附录:
1. 主页面 Index.ets 完整代码
// pages/Index.ets
import { TestFlowControl } from '../utils/TestFlowControl';
import { router } from '@kit.ArkUI';@Entry
@Component
struct Index {aboutToAppear(): void {TestFlowControl.runAllTests();}build() {Column() {Text("ArkTS流程控制").fontSize(24).fontWeight(FontWeight.Bold).textAlign(TextAlign.Center).width('100%').margin({ top: 50 })Text("查看Log面板查看测试结果").fontSize(16).textAlign(TextAlign.Center).width('100%').margin({ top: 20 })Button("进入猜数字小游戏").fontSize(16).width('100%').margin({ top: 20 }).onClick(()=>{router.push({url:"pages/GuessNumberGame"})})Text("核心知识点:\n1. 条件判断:if-else/switch-case\n2. 循环结构:for/for...of/while/do-while\n3. 流程控制:break/continue\n4. 实战案例:猜数字/杨辉三角/99乘法表").fontSize(14).textAlign(TextAlign.Start).width('100%').margin({ top: 40, left: 30 }).lineHeight(24)}.width('100%').height('100%')}}
2. 猜数字小游戏
猜数字小游戏当前阶段只需关注逻辑处理部分,也就是if-else 其他的内容当前我们没有学不用过度关注。
在UI阶段我带领你们重头手搓这个小游戏,希望大家能坚持到UI基础阶段哦。如果我忘了请提醒我哈哈。
import { promptAction, router } from '@kit.ArkUI'@Entry
@Component
struct GuessNumberGame {// 游戏核心状态@State targetNumber: number = this.generateRandomNumber() // 目标数字(1-100)@State userInput: string = '' // 用户输入的字符串@State guessCount: number = 0 // 已猜次数@State maxAttempts: number = 10 // 最大尝试次数@State message: string = '请输入1-100之间的数字开始游戏' // 提示信息@State history: string[] = [] // 历史记录@State isGameOver: boolean = false // 游戏是否结束aboutToAppear(): void {}aboutToDisappear(): void {}// 生成1-100的随机数generateRandomNumber(): number {return Math.floor(Math.random() * 100) + 1}// 重置游戏resetGame() {this.targetNumber = this.generateRandomNumber()this.userInput = ''this.guessCount = 0this.message = '游戏已重置,请重新输入1-100之间的数字'this.history = []this.isGameOver = false}// 处理猜数字逻辑handleGuess() {// 游戏结束时不响应if (this.isGameOver) return// 输入校验const guess = Number(this.userInput)if (isNaN(guess) || guess < 1 || guess > 100) {this.message = '请输入有效的1-100之间的数字!'promptAction.showToast({ message: this.message })return}// 次数递增this.guessCount++const remaining = this.maxAttempts - this.guessCountconst record = `第${this.guessCount}次:${guess}`// 判断大小if (guess > this.targetNumber) {this.message = `猜大了!还剩${remaining}次机会`this.history.unshift(`${record} → 猜大了`)} else if (guess < this.targetNumber) {this.message = `猜小了!还剩${remaining}次机会`this.history.unshift(`${record} → 猜小了`)} else {// 猜对了this.message = `恭喜你猜对了!答案就是${guess},共猜了${this.guessCount}次`this.history.unshift(`${record} → 猜对了!🎉`)this.isGameOver = truereturn}// 次数用完if (remaining === 0) {this.message = `游戏结束!正确答案是${this.targetNumber}`this.history.unshift(`次数用尽 → 正确答案:${this.targetNumber}`)this.isGameOver = true}// 清空输入框this.userInput = ''}build() {Column() {// 游戏标题Text('猜数字小游戏').fontSize(24).fontWeight(FontWeight.Bold).margin(20).onClick(()=>{router.push({url:"pages/nextPage"})})// 游戏规则Text(`规则:猜1-100之间的数字,共${this.maxAttempts}次机会`).fontSize(14).fontColor('#666').margin({ bottom: 20 })// 输入区域Row() {TextInput({placeholder: '请输入数字',text: this.userInput}).type(InputType.Number) // 限制为数字输入.width(200).height(40).border({ width: 1 }).padding(5).onChange((value) => this.userInput = value)Button('猜一下').width(100).height(40).margin({ left: 10 }).onClick(() => this.handleGuess())}.margin({ bottom: 20 })// 提示信息Text(this.message).fontSize(16).fontColor(this.isGameOver ? '#e53935' : '#2e7d32').margin({ bottom: 10 })// 历史记录Text('历史记录:').fontSize(16).fontWeight(FontWeight.Medium).margin({ bottom: 5, top: 10 })Scroll() {Column() {ForEach(this.history, (item:string) => {Text(item).fontSize(14).margin(2).fontColor('#555')})}}.height(200).width('100%').border({ width: 1, style: BorderStyle.Dashed }).padding(5)// 重置按钮Button('重新开始').width(150).height(40).margin({ top: 20 }).backgroundColor('#42a5f5').onClick(() => this.resetGame())}.width('100%').height('100%').padding(15).backgroundColor('#f5f5f5')}
}