散修带你入门鸿蒙应用开发基础第二节:运算符与表达式

ArkTS基础第二节:运算符与表达式

炼气二重天

【学习目标】

  1. 掌握算术、比较、逻辑、赋值、三元运算5类核心基础运算符的语法与用法
  2. 能区分 =====||?? 的核心差异,避开基础踩坑
  3. 理解自增/自减、逻辑运算符的短路特性,会用简单表达式解决问题
  4. 掌握“括号优先”的运算规则,能写出符合预期的简单表达式
  5. 熟练完成本节独立项目的文件搭建与代码运行

【学习重点】

  • 算术运算:+(含字符串拼接)、%(判断奇偶)、++/--(循环常用)
  • 比较运算:同类型比较原则、=== 的优先使用场景
  • 逻辑运算:&&(同时满足)、||(至少一个满足)的基础用法
  • 赋值运算:+=-= 等复合赋值的简化写法
  • 三元运算:简单条件判断的简洁写法
  • 避坑点:不同类型不能直接比较、一行只声明一个变量

一、新建工程项目

本节基于鸿蒙5.0(API12),采用独立项目开发(项目名OperatorDemo)。所有测试方法均统一添加到 utils/TestOperator.ets 类中,无需额外创建文件。

核心文件结构(仅需2个关键文件)

ets/
├── pages/
│   └── Index.ets(主页面,已自动创建,修改内容)
└── utils/
    └── TestOperator.ets(新建,存放所有运算符测试函数)

步骤1:新建TestOperator.ets(测试工具类)

  1. ets目录下右键新建utils文件夹;
  2. 右键utils文件夹 → 新建ArkTS File,命名为TestOperator.ets
  3. 写入基础框架(后续所有测试函数均添加到此类中):
// utils/TestOperator.ets
/**
 * 运算符与表达式测试工具类,所有测试方法集中在此
 */
export class TestOperator {
  /**
   * 统一执行所有测试(主页面调用)
   */
  static runAllTests() {
    console.log("\n===== 第二节:运算符与表达式测试开始 =====");
    // 后续每个测试函数写完后,仅保留当前要测试的调用,其余注释掉
  }
}

步骤2:修改Index.ets(主页面)

打开自动生成的pages/Index.ets,替换为以下代码(承载UI+调用测试):

// pages/Index.ets
import { TestOperator } from '../utils/TestOperator';

@Entry
@Component
struct Index {
  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 })
    }
    .width('100%')
    .height('100%')
  }

  // 页面加载时自动执行所有测试
  aboutToAppear(): void {
    TestOperator.runAllTests();
  }
}

步骤3:运行验证环境

保存所有文件后,直接运行项目(使用已创建的模拟器/真实设备/预览模式),打开底部「Log」面板,看到“测试开始”日志即说明环境搭建成功。

核心操作规则:学习每个运算符模块时,仅在 runAllTests 中调用当前模块的测试函数,之前的函数用 // 注释掉,专注单个知识点测试,无需关心“静态函数”概念,只看函数内代码逻辑。

二、算术运算符:处理数值计算

算术运算符是最基础的计算工具,重点掌握常用场景和特殊用法,严格遵循“一行一个变量”规范。

1.1 基础算术运算符(含字符串拼接)

操作步骤:

  1. TestOperator 类中添加 testArithmeticBasic 静态函数;
  2. runAllTests 中调用该函数(无需其他配置)。
// utils/TestOperator.ets(完整代码片段)
export class TestOperator {
  static runAllTests() {
    console.log("\n===== 第二节:运算符与表达式测试开始 =====");
    TestOperator.testArithmeticBasic(); // 仅启用当前测试函数
    // 后续其他函数调依次添加,且要注释掉上一次的。
  }

  /**
   * 测试基础算术运算符(+、-、*、/、%)及字符串拼接
   * 规范:一行一个变量,提升可读性
   */
  static testArithmeticBasic() {
    console.log("\n===== 基础算术运算测试 =====");
    // 1. 数值计算(一行一个变量,拒绝逗号分隔)
    let num1: number = 10;
    let num2: number = 3;
    console.log(`${num1} + ${num2} = ${num1 + num2}`); // 13
    console.log(`${num1} - ${num2} = ${num1 - num2}`); // 7
    console.log(`${num1} * ${num2} = ${num1 * num2}`); // 30
    console.log(`${num1} / ${num2} = ${num1 / num2}`); // 3.3333333333333335
    console.log(`${num1} % ${num2} = ${num1 % num2}`); // 1(余数,用于判断奇偶)

    // 2. 字符串拼接(+号的双重用途)
    let name: string = "李四";
    // 传统拼接(+号)
    console.log("欢迎 " + name + " 学习ArkTS!"); // 欢迎 李四 学习ArkTS!
    // 模板字符串拼接(推荐,支持动态插入变量)
    console.log(`欢迎 ${name} 学习ArkTS!`); // 欢迎 李四 学习ArkTS!

    // 3. 实用场景:判断奇偶(结合三元运算符)
    let age: number = 23;
    const parity: string = age % 2 === 0 ? "偶数" : "奇数";
    console.log(`${age} 是${parity}`); // 23 是奇数
  }
}

运行验证

保存代码后运行项目,在Log面板中查看“基础算术运算测试”相关日志,验证数值计算结果和字符串拼接效果是否正确。

1.2 自增(++)与自减(--)(循环常用)

操作步骤:

  1. 注释掉 testArithmeticBasic 的调用;
  2. TestOperator 类中添加 testIncrementDecrement 函数;
  3. runAllTests 中调用该函数。
// utils/TestOperator.ets(新增函数片段)
static runAllTests() {
  console.log("\n===== 第二节:运算符与表达式测试开始 =====");
  // TestOperator.testArithmeticBasic(); // 注释之前的测试函数
  TestOperator.testIncrementDecrement(); // 启用当前测试函数
}

/**
 * 测试自增(++)与自减(--)运算符
 * 核心:单独用无差异,表达式中看位置(前置先运算后取值,后置先取值后运算)
 */
static testIncrementDecrement() {
  console.log("\n===== 自增自减运算测试 =====");
  // 1. 单独使用(前置/后置完全一致,推荐用count++)
  let count: number = 0;
  count++; // 等价于 count = count + 1
  console.log(`count++ 后:${count}`); // count++ 后:1

  count--; // 等价于 count = count - 1
  console.log(`count-- 后:${count}`); //  count-- 后:0

  // 2. 表达式中使用(基础阶段重点理解)
  let x: number = 3;
  let y: number = x++; // 步骤:先取x=3赋值给y → 再x自增为4
  let z: number = ++x; // 步骤:先x自增为5 → 再取x=5赋值给z
  console.log(`x=${x}, y=${y}, z=${z}`); // 输出:x=5, y=3, z=5

  // 3. 循环常用场景(后置++最普遍)
  console.log("循环输出0-4:");
  for (let i: number = 0; i < 5; i++) { // 先判断i是否满足条件,再自增
      console.log(`${i}`); // 0,1,2,3,4
  }
}

运行验证

查看Log面板中“自增自减运算测试”日志,重点关注 x、y、z 的值是否符合预期,理解“前置先运算后取值,后置先取值后运算”的规则。

三、比较运算符:判断数据关系(核心是“同类型比较”)

比较运算符返回 true(成立)或 false(不成立),ArkTS是强类型语言,不同类型直接比较会编译报错,优先使用===

/**
 * 测试比较运算符(>、<、>=、<=、===、!==)及 === vs == 核心差异
 * 核心:同类型比较,优先用===(严格相等)
 */
static testComparison() {
  console.log("\n===== 比较运算符测试 =====");
  // 声明变量(一行一个,类型明确)
  const num: number = 5;
  const str: string = "5";
  const nul: string|null = null;
  const undef: string|undefined = undefined;

  // 1. 合法比较(同类型比较,编译通过)
  console.log(`5 === 5(数字同类型):${num === 5}`); // true
  console.log(`"a" === "str"(字符串):${"a" === str}`); // false
  console.log(`"b" > "a"(字符串按Unicode排序):${"b" > "a"}`); // true
  console.log(`10 >= 8(数字范围):${10 >= 8}`); // true
  console.log(`null == undefined(特殊允许组合):${nul == undef}`); // true
  console.log(`null === undefined(类型不同):${nul === undef}`); // false

  // 2. 实战场景:表单输入验证(先转类型再比较)
  const inputAge: string = "18"; // 表单输入默认是字符串
  const age: number = Number(inputAge); // 转为数字类型(关键步骤)
  console.log(`输入年龄是否等于18:${age === 18}`); // true
  console.log(`输入年龄是否>=18:${age >= 18}`); // true

  // 3. 非法比较(不同类型,编译报错,勿模仿)
  console.log("\n===== 非法比较示例(编译报错)=====");
  console.log("错误写法1:num == str(数字 vs 字符串)");
  console.log("错误写法2:0 == ''(数字 vs 空字符串)");
  console.log("结论:不同类型需先转类型,再用===比较");
}

运行验证

查看Log面板,重点关注 ===== 的差异,以及“先转类型再比较”的实战场景,理解“同类型比较”的核心原则。

四、逻辑运算符:组合条件判断

逻辑运算符用于组合多个比较条件,返回 truefalse,重点掌握 &&(并且)、||(或者)的基础用法和短路特性,以及 ??|| 的差异。

4.1 基础逻辑运算(&&、||、!)


static testLogic() {
  // 准备测试变量(模拟用户状态)
  const isLogin: boolean = true; // 模拟用户已登录
  const hasPermission: boolean = false; // 模拟无操作权限
  console.log("\n===== 4. 基础逻辑运算符测试 =====");

  // 逻辑与(&&):两边都为true时,整体结果才为true(类似“并且”)
  console.log(`5>3 且 8>6:${5 > 3 && 8 > 6}`); // true(两边都成立)
  console.log(`5>3 且 8<6:${5 > 3 && 8 < 6}`); // false(右边不成立)
  // 常用场景:多条件同时满足才执行(结合if语句演示,下节课详解)
  if (isLogin && hasPermission) {
    console.log(` 逻辑与:已登录(${isLogin}) 且 有权限(${hasPermission}) → 条件成立`);
  } else {
    console.log(` 逻辑与:已登录(${isLogin}) 且 有权限(${hasPermission}) → 条件不成立`);
  }


  // 逻辑或(||):至少一边为true时,整体结果就为true(类似“或者”)
  console.log(`5>3 或 8<6:${5 > 3 || 8 < 6}`); // true(左边成立)
  console.log(`5<3 或 8<6:${5 < 3 || 8 < 6}`); // false(两边都不成立)
  // 常用场景:满足任一条件即可执行(如“管理员或VIP可享受优惠”)
  const isAdmin: boolean = false;
  const isVip: boolean = true;
  console.log(`是管理员(${isAdmin}) 或 是VIP(${isVip}) → 可享优惠:${isAdmin || isVip}`); // true(VIP可享受)
  
  // 用if语句演示:任意条件成立就执行
  if (isAdmin || isVip) {
    console.log(" 逻辑或:任意一个条件成立,执行此语句");
  }


  // 逻辑非(!):对布尔值取反(true→false,false→true)
  console.log(`并非 5>3:${!(5 > 3)}`); // false(5>3是true,取反为false)
  console.log(`并非 5<3:${!(5 < 3)}`); // true(5<3是false,取反为true)

  // 常用场景:按钮点击状态切换(通过!取反实现“点击切换”)
  let isPress: boolean = false; // 默认未点击
  console.log(`按钮状态默认值:${isPress}`); // false
  isPress = !isPress; // 第一次点击:取反为true(已点击)
  console.log(`按钮点击第一次:${isPress}`); // true
  isPress = !isPress; // 第二次点击:再次取反为false(未点击)
  console.log(`按钮状态第二次:${isPress}`); // false


  // 短路特性:左边已确定结果时,右边表达式不执行(优化性能)
  console.log("\n===== 短路特性测试 =====");

  // 逻辑与(&&)短路:左边为false时,右边不执行
  console.log(`5<3 && console.log("执行方法"):${5 < 3 && console.log("执行方法")}`);
  // 解析:5<3是false,整体结果已确定,右边的console.log("执行方法")不执行,输出false
  
  // 常用场景:前置条件不满足时,不执行后续操作(如“未登录则不加载数据”)
  console.log(`未登录(${!isLogin}) → 不加载数据:${!isLogin && "加载用户数据"}`); // false(未登录为false,不执行加载)


  // 逻辑或(||)短路:左边为true时,右边不执行
  console.log(`5>3 || console.log("执行方法"):${5 > 3 || console.log("执行方法")}`);
  // 解析:5>3是true,整体结果已确定,右边的console.log("执行方法")不执行,输出true
  
  // 常用场景:有有效值时,不使用默认值(如“用户填了昵称则不用默认名”)
  const userNickname: string = "小明"; // 模拟用户已填昵称
  console.log(`用户昵称:${userNickname || "游客"}`); // 输出“小明”(已有值,不使用默认名)
}

运行验证

查看Log面板,观察短路特性是否生效(右边的 console.log 未打印),理解逻辑运算符的判断规则。

4.2 空值合并运算符 ??|| 的差异

/**
 * 测试空值合并运算符(??)与逻辑或(||)的核心差异
 * 核心:?? 仅处理null/undefined,|| 处理所有假值(0、""、false等)
 */
static testNullishCoalescing() {
  console.log("\n===== ?? 与 || 差异测试 =====");
  // 场景1:值为null/undefined(真正的空值)
  const userName1: string | null = null;
  const userName2: string | undefined = undefined;
  console.log(`userName1(null)?? 匿名用户:${userName1 ?? "匿名用户"}`); // 匿名用户
  console.log(`userName2(undefined)?? 匿名用户:${userName2 ?? "匿名用户"}`); // 匿名用户

  // 场景2:值为空字符串/0(合法输入,非空值)
  const userName3: string = ""; // 空字符串是合法输入
  const userAge: number = 0; // 0是合法数值
  console.log(`userName3(空字符串)?? 匿名用户:${userName3 ?? "匿名用户"}`); // 保留空字符串
  console.log(`userAge(0)?? 18:${userAge ?? 18}`); // 保留0

  // 对比:|| 会误处理合法假值
  console.log(`userName3(空字符串)|| 匿名用户:${userName3 || "匿名用户"}`); // 误触发为匿名用户
  console.log(`userAge(0)|| 18:${userAge || 18}`); // 误触发为18

  console.log("结论:设置默认值优先用??,避免||误处理合法假值");
}

运行验证

查看Log面板,对比 ??|| 对空字符串、0的处理差异,记住“默认值用??”的最佳实践。

五、赋值运算符:简化“运算+赋值”

赋值运算符将运算结果赋值给变量,复合赋值(+=/-= 等)是“变量=变量+运算数”的简化写法,提升代码简洁度。

/**
 * 测试赋值运算符(=、+=、-=、*=、/=、%=)
 * 核心:复合赋值是"运算+赋值"的简化写法
 */
static testAssignment() {
  console.log("\n===== 赋值运算符测试 =====");
  // 1. 基础赋值(=):初始化变量
  let num: number = 10;
  console.log(`初始值:num = ${num}`); // 10

  // 2. 复合赋值(简化写法)
  num += 5; // 等价于 num = num + 5
  console.log(`num +=5 后:${num}`); // 15

  num *= 2; // 等价于 num = num * 2
  console.log(`num *=2 后:${num}`); // 30

  num %= 7; // 等价于 num = num % 7(取余后赋值)
  console.log(`num %=7 后:${num}`); // 2(30÷7=4余2)

  num -= 1; // 等价于 num = num - 1
  console.log(`num -=1 后:${num}`); // 1

  // 3. 字符串拼接赋值(+= 同样适用)
  let greeting: string = "Hello";
  greeting += " "; // 等价于 greeting = greeting + " "
  greeting += "ArkTS!"; // 等价于 greeting = greeting + "ArkTS!"
  console.log(`字符串拼接后:${greeting}`); // Hello ArkTS!
}

运行验证

查看Log面板,验证复合赋值的结果是否与“完整写法”一致,掌握 += 既可以用于数值运算,也可以用于字符串拼接。

六、三元运算符:简单条件判断

三元运算符(condition ? exprIfTrue : exprIfFalse)是 if-else 的简化写法,适合简单二选一/三选一逻辑,核心是“条件成立取前面,不成立取后面”。

/**
 * 测试三元运算符(条件 ? 成立值 : 不成立值)
 * 核心:简单条件用三元,复杂条件后续用if-else
 */
static testTernary() {
  console.log("\n===== 三元运算符测试 =====");
  // 1. 基础用法:二选一(判断成年/未成年)
  const age: number = 17;
  const adultStatus: string = age >= 18 ? "成年" : "未成年";
  console.log(`年龄${age}:${adultStatus}`); // 未成年

  // 2. 嵌套用法:三选一(判断数字正负,最多嵌套2层)
  const num: number = -3;
  const numType: string = num > 0 ? "正数" : num === 0 ? "零" : "负数";
  console.log(`数字${num}是:${numType}`); // 负数

  // 3. 结合逻辑运算:区间判断(60-80为及格)
  const score: number = 75;
  const scoreDesc: string = score >= 60 && score < 80 ? "及格" : score >= 80 ? "优秀" : "不及格";
  console.log(`分数${score}:${scoreDesc}`); // 及格

  // 4. 结合算术运算:求两数最大值
  const a: number = 10;
  const b: number = 20;
  const maxNum: number = a > b ? a : b;
  console.log(`a=${a}, b=${b},较大值是:${maxNum}`); // 20
}

运行验证

查看Log面板,验证不同条件下三元运算符的返回结果是否正确,记住“嵌套不超过2层”的规则。

七、表达式与运算优先级

运算符组合形成表达式,运算优先级决定执行顺序,核心原则:不确定就加括号 (),既安全又易读

/**
 * 测试表达式与运算优先级
 * 优先级从高到低:括号() → 算术(*、/、%)→ 算术(+、-)→ 比较 → 逻辑 → 三元 → 赋值
 */
static testExpressionPriority() {
  console.log("\n===== 表达式与运算优先级测试 =====");
  // 1. 括号改变优先级(括号优先级最高)
  console.log(`10 + 20 * 2 = ${10 + 20 * 2}`); // 50(先乘后加,默认优先级)
  console.log(`(10 + 20) * 2 = ${(10 + 20) * 2}`); // 60(括号优先,先加后乘)

  // 2. 比较+逻辑运算(先比较,后逻辑)
  const logicRes: boolean = 10 + 5 > 12 && 3 < 5;
  console.log(`10 + 5 > 12 && 3 < 5 = ${logicRes}`); // true(步骤:15>12→true,3<5→true,true&&true→true)

  // 3. 三元+算术运算(先算术/比较,后三元)
  const ternaryRes: number = 10 > 5 ? 20 * 3 : 10 / 2;
  console.log(`10>5 ? 20*3 : 10/2 = ${ternaryRes}`); // 60(先判断10>5,再计算20*3)

  // 4. 复杂表达式(结合多种运算符)
  const x: number = 5;
  const y: number = 3;
  const complexRes: number = (x + y) * 2 - 8 / 4;
  console.log(`(5+3)*2 - 8/4 = ${complexRes}`); // 14(步骤:8*2=16 → 8/4=2 → 16-2=14)

  console.log("结论:不确定优先级就加括号,避免逻辑错误");
}

运行验证

查看Log面板,对比有无括号的运算结果差异,理解“括号改变优先级”的核心作用,记住简化优先级顺序:算术运算 > 比较运算 > 逻辑运算 > 三元运算 > 赋值运算。

八、完整测试(可选)

所有模块学习完成后,可取消所有注释,一次性运行所有测试函数,验证整体逻辑:

// utils/TestOperator.ets(完整运行配置)
static runAllTests() {
  console.log("\n===== 第二节:运算符与表达式测试开始 =====");
  TestOperator.testArithmeticBasic();
  TestOperator.testIncrementDecrement();
  TestOperator.testComparison();
  TestOperator.testLogic();
  TestOperator.testNullishCoalescing();
  TestOperator.testAssignment();
  TestOperator.testTernary();
  TestOperator.testExpressionPriority();
  console.log("===== 第二节:运算符与表达式测试结束 =====");
}

【课堂小结】

  1. 编码规范:严格遵循“一行一个变量”,拒绝逗号分隔声明;
  2. 核心运算符:
    • 算术运算:% 判奇偶,++/-- 注意表达式中位置;
    • 比较运算:同类型比较,优先用 ===
    • 逻辑运算:&&|| 支持短路,默认值用 ??
    • 赋值运算:复合赋值简化代码,+= 通用字符串/数值;
    • 三元运算:简单逻辑简化写法,嵌套不超过2层;
  3. 避坑重点:不同类型不直接比较、不确定优先级就加括号。

【课后练习】

  1. 操作题:在TestOperator中添加testDivideAndRemainder方法,声明x=15(一行一个变量),计算除以4的商(向下取整)和余数,用模板字符串打印“15除以4,商=3,余数=3”。
  2. 操作题:添加testRangeCheck方法,声明num=73,用三元运算符判断是否在1-100之间,打印“73在1-100之间”或“73超出1-100范围”。
  3. 分析题:在testIncrementAnalysis方法中执行let a=3; let b=++a + a++;,打印ab的值并解释执行过程。
  4. 操作题:添加testDefaultValue方法,声明score: number | null = 0score2: number | null = null(一行一个变量),分别用??||设置默认值60,打印4个结果并说明差异。
  5. 操作题:添加testNumberProcess方法,声明num=-8,用三元运算符判断是否为正数,是则返回平方(num*num),否则返回绝对值(Math.abs(num))并打印。
  6. 改错题:添加testFixError方法,修复以下代码并说明错误原因:
    let num: number = 5, str: string = "5"; // 错误1
    console.log(num == str); // 错误2
    

【代码仓库】

第二节项目代码(OperatorDemo)已同步:https://gitee.com/juhetianxia321/harmony-os-code-base.git

【下节预告】

第三节将进入流程控制核心章节,系统学习程序的“决策与重复”能力:重点掌握if-else分支、if-else if-else多分支、switch-case固定值匹配的语法与场景差异;深入理解for(已知次数)、for...of(简洁遍历)、while/do-while(条件驱动)的核心用法,以及break(终止循环)与continue(跳过当前轮)的流程控制技巧;同时结合猜数字游戏、杨辉三角、99乘法表等实战案例,强化逻辑思维,让你能独立用流程控制解决复杂重复或多条件判断问题。

鸿蒙开发者学习与认证指引

(一)、官方学习班级报名(免费)

  1. 班级链接HarmonyOS赋能资源丰富度建设(第四期)
  2. 学号填写规则:填写个人手机号码即可完成班级信息登记

(二)、HarmonyOS应用开发者认证考试(免费)

  1. 考试链接HarmonyOS开发者能力认证入口

  2. 认证等级及适配人群

    • 基础认证:适配软件工程师、移动应用开发人员,需掌握HarmonyOS基础概念、DevEco Studio基础使用、ArkTS及ArkUI基础开发等能力;
    • 高级认证:适配项目经理、工程架构师,需掌握系统核心技术理念、应用架构设计、关键技术开发及应用上架运维等能力;
    • 专家认证:适配研发经理、解决方案专家,需掌握分布式技术原理、端云一体化开发、跨端迁移及性能优化等高级能力。
  3. 认证权益:通过认证可获得电子版证书以及其他专属权益。

posted @ 2025-12-08 16:16  鸿蒙-散修  阅读(0)  评论(0)    收藏  举报