零基础鸿蒙应用开发第四节:运算符与运算规则
【学习目标】
- 掌握算术、比较、逻辑、赋值、三元运算5类核心基础运算符的语法与用法
- 能区分
==与===、||与??的核心差异,避开基础踩坑 - 理解自增/自减、逻辑运算符的短路特性,会用简单表达式解决问题
- 掌握“括号优先”的运算规则,能写出符合预期的简单表达式
- 掌握
typeof运算符的用法,能正确检测值的类型
【学习重点】
- 核心用法:5类基础运算符的语法与实际应用场景
- 避坑要点:
==与===、||与??的差异,以及如何正确选择使用 - 特性掌握:自增/自减的前置/后置区别、逻辑运算符的短路特性
- 规则应用:运算优先级(括号优先)的实际使用,确保表达式结果符合预期
- 类型检测:
typeof运算符的使用及特殊情况处理
特别说明:本节内容是变量与基本类型的延伸,所有运算符操作均基于前一节的
number、string、boolean类型展开,重点关注表达式的运算逻辑与结果。
一、工程结构
本节我们将创建名为OperatorDemo的工程,基于鸿蒙5.0(API12)开发,使用DevEco Studio 6.0+工具,项目结构目录如下:
OperatorDemo
├── AppScope # 应用全局配置目录
├── entry # 主模块目录(核心业务模块)
│ ├── .preview # 预览相关配置
│ ├── src
│ │ ├── main
│ │ │ ├── ets # ArkTS 代码核心目录
│ │ │ │ ├── entryability # 应用入口能力(程序启动/生命周期)
│ │ │ │ ├── pages # 页面UI目录
│ │ │ │ │ └── Index.ets # 核心页面(调用工具函数)
│ │ │ │ └── utils # 工具函数目录
│ │ │ │ └── TestOperator.ets # 本节所有学习内容
│ │ │ ├── resources # 静态资源目录
│ │ │ └── module.json5 # 模块配置文件
│ │ ├── ohosTest # 鸿蒙端测试目录
│ │ └── test # 单元测试目录
│ ├── build-profile.json5 # 构建配置文件
│ ├── hvigorfile.ts # 构建脚本
│ └── oh-package.json5 # 依赖包配置文件
├── hvigor # 构建工具依赖
└── oh_modules # 第三方依赖包目录
开发准备步骤
- 打开DevEco Studio,创建
OperatorDemo项目(选择Empty Ability模板,API12/鸿蒙5.0); - 在
src/main/ets目录下右键创建utils文件夹; - 选中
utils文件夹,右键创建OperatorTest.ets文件(存放所有运算符); - 所有业务函数统一在
Index.ets的aboutToAppear生命周期中调用。
二、基本算术运算符
算术运算符用于处理数值的数学运算,包括基本算术运算和自增/自减运算,是最基础的运算符类型。
| 运算符 | 名称 | 示例 | 说明 |
|---|---|---|---|
+ |
加法 | 10 + 5 |
数值相加/字符串拼接 |
- |
减法 | 10 - 5 |
数值相减 |
* |
乘法 | 10 * 5 |
数值相乘 |
/ |
除法 | 10 / 5 |
数值相除(结果为浮点数) |
% |
取余(模) | 10 % 3 |
取除法的余数 |
2.1 代码逻辑封装
// src/main/ets/utils/OperatorTest.ets
/**
* 算术运算符相关逻辑:基本运算、字符串拼接、自增自减
*/
export function arithmeticOperators(): void {
// 1. 基本算术运算
const num1: number = 10;
const 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.333...
console.log(`【算术运算】${num1} % ${num2} = ${num1 % num2}`); // 1
// 2. +运算符的特殊用法:字符串拼接(强类型推荐显式转换)
const str1: string = "Hello";
const str2: string = "ArkTS";
console.log(`【算术运算】字符串拼接:${str1 + " " + str2}`); // Hello ArkTS
const age: number = 20;
const user: string = "年龄:" + age; // 隐式转换,不推荐
console.log(`【算术运算】隐式转换拼接:${user}`); // 年龄:20
const info: string = "年龄:" + age.toString(); // 显式转换,推荐
console.log(`【算术运算】强类型拼接:${info}`); // 年龄:20
// 3. 自增/自减运算
let a: number = 5;
console.log(`【自增运算】a++ = ${a++}`); // 先输出5,再自增(a变为6)
console.log(`【自增运算】自增后a = ${a}`); // 6
console.log(`【自增运算】++a = ${++a}`); // 先自增(a变为7),再输出7
console.log(`【自增运算】自增后a = ${a}`); // 7
let b: number = 5;
console.log(`【自减运算】b-- = ${b--}`); // 先输出5,再自减(b变为4)
console.log(`【自减运算】自减后b = ${b}`); // 4
console.log(`【自减运算】--b = ${--b}`); // 先自减(b变为3),再输出3
console.log(`【自减运算】自减后b = ${b}`); // 3
}
2.2 运行效果
【算术运算】10 + 3 = 13
【算术运算】10 - 3 = 7
【算术运算】10 * 3 = 30
【算术运算】10 / 3 = 3.3333333333333335
【算术运算】10 % 3 = 1
【算术运算】字符串拼接:Hello ArkTS
【算术运算】隐式转换拼接:年龄:20
【算术运算】强类型拼接:年龄:20
【自增运算】a++ = 5
【自增运算】自增后a = 6
【自增运算】++a = 7
【自增运算】自增后a = 7
【自减运算】b-- = 5
【自减运算】自减后b = 4
【自减运算】--b = 3
【自减运算】自减后b = 3
三、赋值运算符
赋值运算符用于将右侧的值赋给左侧的变量,包括基本赋值和复合赋值(结合算术运算符)。
3.1 赋值运算符列表
| 运算符 | 名称 | 示例 | 等价于 |
|---|---|---|---|
= |
基本赋值 | a = 10 |
- |
+= |
加法赋值 | a += 5 |
a = a + 5 |
-= |
减法赋值 | a -= 5 |
a = a - 5 |
*= |
乘法赋值 | a *= 5 |
a = a * 5 |
/= |
除法赋值 | a /= 5 |
a = a / 5 |
%= |
取余赋值 | a %= 5 |
a = a % 5 |
3.2 代码逻辑封装
// src/main/ets/utils/OperatorTest.ets
/**
* 赋值运算符相关逻辑:基本赋值、复合赋值
*/
export function assignmentOperators(): void {
let num: number = 10;
console.log(`\n【赋值运算】初始num = ${num}`); // 10
// 基本赋值
num = 20;
console.log(`【赋值运算】num = 20 → ${num}`); // 20
// 复合赋值
num += 5;
console.log(`【赋值运算】num += 5 → ${num}`); // 25
num -= 3;
console.log(`【赋值运算】num -= 3 → ${num}`); // 22
num *= 2;
console.log(`【赋值运算】num *= 2 → ${num}`); // 44
num /= 4;
console.log(`【赋值运算】num /= 4 → ${num}`); // 11
num %= 3;
console.log(`【赋值运算】num %= 3 → ${num}`); // 2
}
3.3 运行效果
【赋值运算】初始num = 10
【赋值运算】num = 20 → 20
【赋值运算】num += 5 → 25
【赋值运算】num -= 3 → 22
【赋值运算】num *= 2 → 44
【赋值运算】num /= 4 → 11
【赋值运算】num %= 3 → 2
四、比较运算符与typeof类型检测
4.1 比较运算符(大小/相等性)
| 运算符 | 名称 | 示例 | 说明 |
|---|---|---|---|
> |
大于 | 10 > 5 |
返回true |
< |
小于 | 10 < 5 |
返回false |
>= |
大于等于 | 10 >= 10 |
返回true |
<= |
小于等于 | 10 <= 5 |
返回false |
== |
松散相等(值相等) | null == undefined |
返回true |
=== |
严格相等(值+类型) | null === undefined |
返回false |
!= |
松散不相等 | null != undefined |
返回false |
!== |
严格不相等 | null !== undefined |
返回true |
4.2 typeof类型检测
| 运算符 | 名称 | 示例 | 说明 |
|---|---|---|---|
typeof |
类型检测 | typeof 10 |
返回值的类型字符串(如number、string) |
关键说明
typeof是一元运算符(非函数),typeof null返回object(JS历史遗留问题,ArkTS/TS遵循此规则);- 强类型环境下,
typeof常用于运行时类型校验,配合条件语句处理不同类型数值。
4.3 代码逻辑封装
// src/main/ets/utils/OperatorTest.ets
/**
* 比较与typeof运算符相关逻辑:大小比较、类型检测、相等性比较
*/
export function comparisonAndTypeofOperators(): void {
// 1. 大小比较运算
const numA: number = 10;
const numB: number = 5;
console.log(`\n【比较运算-大小】${numA} > ${numB} → ${numA > numB}`); // true
console.log(`【比较运算-大小】${numA} < ${numB} → ${numA < numB}`); // false
console.log(`【比较运算-大小】${numA} >= ${numA} → ${numA >= numA}`); // true
console.log(`【比较运算-大小】${numA} <= ${numB} → ${numA <= numB}`); // false
// 2. typeof类型检测运算
const n: null = null;
const u: undefined = undefined;
console.log(`\n【typeof运算】typeof ${numA} → ${typeof numA}`); // number
console.log(`【typeof运算】typeof "10" → ${typeof "10"}`); // string
console.log(`【typeof运算】typeof ${true} → ${typeof true}`); // boolean
console.log(`【typeof运算】typeof ${n} → ${typeof n}`); // object(历史遗留问题)
console.log(`【typeof运算】typeof ${u} → ${typeof u}`); // undefined
// 3. 相等性比较运算
console.log(`\n【比较运算-相等性】null == undefined → ${n == u}`); // true
console.log(`【比较运算-相等性】null === undefined → ${n === u}`); // false
console.log(`【比较运算-相等性】null != undefined → ${n != u}`); // false
console.log(`【比较运算-相等性】null !== undefined → ${n !== u}`); // true
}
4.4 运行效果
【比较运算-大小】10 > 5 → true
【比较运算-大小】10 < 5 → false
【比较运算-大小】10 >= 10 → true
【比较运算-大小】10 <= 5 → false
【typeof运算】typeof 10 → number
【typeof运算】typeof "10" → string
【typeof运算】typeof true → boolean
【typeof运算】typeof null → object
【typeof运算】typeof undefined → undefined
【比较运算-相等性】null == undefined → true
【比较运算-相等性】null === undefined → false
【比较运算-相等性】null != undefined → false
【比较运算-相等性】null !== undefined → true
五、逻辑运算符
逻辑运算符用于对布尔值进行逻辑运算,重点掌握短路特性和||与??的核心差异。
5.1 逻辑运算符列表
| 运算符 | 名称 | 示例 | 基本说明 | 短路特性 |
|---|---|---|---|---|
&& |
逻辑与 | a && b |
两者都为true,才返回true | 若a为false,直接返回a,不再执行b(短路) |
|| |
逻辑或 | a || b |
两者有一个为true,就返回true | 若a为true,直接返回a,不再执行b(短路) |
! |
逻辑非 | !a |
取反,true变false,反之亦然 | 无短路特性 |
?? |
空值合并 | a ?? b |
若a为null/undefined,返回b | 若a不为null/undefined,直接返回a,不再执行b(短路) |
5.2 代码逻辑封装
// src/main/ets/utils/OperatorTest.ets
/**
* 逻辑运算符相关逻辑:基础运算、|| vs ??、短路特性实用场景
*/
export function logicalOperators(): void {
// 1. 逻辑与/或/非(含短路特性)
const bool1: boolean = true;
const bool2: boolean = false;
console.log(`\n【逻辑运算】${bool1} && ${bool2} → ${bool1 && bool2}`); // false
console.log(`【逻辑运算】${bool2} && ${bool1} → ${bool2 && bool1}`); // false(短路,直接返回bool2)
console.log(`【逻辑运算】10 && 20 → ${10 && 20}`); // 20(都为真,返回最后一个)
console.log(`【逻辑运算】0 && 20 → ${0 && 20}`); // 0(第一个为假,短路返回0)
console.log(`【逻辑运算】${bool1} || ${bool2} → ${bool1 || bool2}`); // true(短路,直接返回bool1)
console.log(`【逻辑运算】${bool2} || ${bool1} → ${bool2 || bool1}`); // true
console.log(`【逻辑运算】0 || 20 → ${0 || 20}`); // 20(0是假值)
console.log(`【逻辑运算】"" || "ArkTS" → ${"" || "ArkTS"}`); // ArkTS(""是假值)
console.log(`【逻辑运算】!${bool1} → ${!bool1}`); // false
console.log(`【逻辑运算】!${bool2} → ${!bool2}`); // true
console.log(`【逻辑运算】!0 → ${!0}`); // true(0是假值)
console.log(`【逻辑运算】!!10 → ${!!10}`); // true(双重取反还原布尔值)
// 2. || 与 ?? 对比
const strB: string = "";
const n: null = null;
const u: undefined = undefined;
console.log(`\n【逻辑运算】0 || 20 → ${0 || 20}`); // 20(0是假值)
console.log(`【逻辑运算】0 ?? 20 → ${0 ?? 20}`); // 0(0不是空值)
console.log(`【逻辑运算】"" || "ArkTS" → ${"" || "ArkTS"}`); // ArkTS(""是假值)
console.log(`【逻辑运算】"" ?? "ArkTS" → ${"" ?? "ArkTS"}`); // ""(""不是空值)
console.log(`【逻辑运算】null ?? "ArkTS" → ${n ?? "ArkTS"}`); // ArkTS(null是空值)
console.log(`【逻辑运算】undefined ?? "ArkTS" → ${u ?? "ArkTS"}`); // ArkTS(undefined是空值)
// 3. 短路特性的实际应用
console.log(`\n【逻辑运算】短路特性实用场景`);
const hasPermission = true;
hasPermission && console.log("✅ 执行权限相关操作"); // 条件满足,执行函数
const userAvatar: string | null = null;
userAvatar ?? console.log("⚠️ 用户未设置头像"); // 空值,执行提示
// 业务场景:商品库存(0是有效数值,需保留)
const stock = 0;
const showStock1 = stock || "库存未知"; // 错误:0被当作假值
const showStock2 = stock ?? "库存未知"; // 正确:保留0
console.log(`【业务场景】stock || "库存未知" → ${showStock1}`); // 库存未知
console.log(`【业务场景】stock ?? "库存未知" → ${showStock2}`); // 0
}
5.3 运行效果
【逻辑运算】true && false → false
【逻辑运算】false && true → false
【逻辑运算】10 && 20 → 20
【逻辑运算】0 && 20 → 0
【逻辑运算】true || false → true
【逻辑运算】false || true → true
【逻辑运算】0 || 20 → 20
【逻辑运算】"" || "ArkTS" → ArkTS
【逻辑运算】!true → false
【逻辑运算】!false → true
【逻辑运算】!0 → true
【逻辑运算】!!10 → true
【逻辑运算】0 || 20 → 20
【逻辑运算】0 ?? 20 → 0
【逻辑运算】"" || "ArkTS" → ArkTS
【逻辑运算】"" ?? "ArkTS" → ""
【逻辑运算】null ?? "ArkTS" → ArkTS
【逻辑运算】undefined ?? "ArkTS" → ArkTS
【逻辑运算】短路特性实用场景
✅ 执行权限相关操作
⚠️ 用户未设置头像
【业务场景】stock || "库存未知" → 库存未知
【业务场景】stock ?? "库存未知" → 0
六、三元运算符(条件运算符)
三元运算符是简化的if-else语句,语法为条件表达式 ? 表达式1 : 表达式2,适用于简单二选一判断。
6.1 代码逻辑封装
// src/main/ets/utils/OperatorTest.ets
/**
* 三元运算符相关逻辑:基本用法、嵌套、实用场景
*/
export function ternaryOperators(): void {
// 1. 基本用法(成绩及格判断)
const score: number = 85;
const result: string = score >= 60 ? "及格" : "不及格";
console.log(`\n【三元运算】成绩${score} → ${result}`); // 及格
// 2. 嵌套用法(成绩等级判断)
const grade: string = score >= 90 ? "优秀" : (score >= 80 ? "良好" : (score >= 60 ? "及格" : "不及格"));
console.log(`【三元运算】成绩${score} → 等级${grade}`); // 良好
// 3. 实用场景(绝对值/库存提示)
const numD: number = -15;
const absNum: number = numD >= 0 ? numD : -numD;
console.log(`【三元运算】${numD}的绝对值 → ${absNum}`); // 15
const stockNum: number = 0;
const stockTip: string = stockNum > 0 ? `库存充足(${stockNum}件)` : (stockNum === 0 ? "库存告急" : "库存未知");
console.log(`【三元运算】库存提示 → ${stockTip}`); // 库存告急
}
6.2 运行效果
【三元运算】成绩85 → 及格
【三元运算】成绩85 → 等级良好
【三元运算】-15的绝对值 → 15
【三元运算】库存提示 → 库存告急
七、运算优先级与括号优先规则
当表达式中有多个运算符时,会按优先级执行,括号()拥有最高优先级,可强制改变执行顺序。
7.1 运算优先级(从高到低)
- 括号
() - 自增
++/自减--、逻辑非!、typeof - 算术运算符(
*///%>+/-) - 比较运算符(
>/</>=/<=>==/===/!=/!==) - 逻辑与
&& - 逻辑或
||、空值合并?? - 三元运算符
? : - 赋值运算符
=/+=/-=等
7.2 代码逻辑封装
// src/main/ets/utils/OperatorTest.ets
/**
* 运算优先级相关逻辑:括号优先、不同运算符优先级演示
*/
export function operatorPrecedence(): void {
// 示例1:算术运算符优先级(* > +)
const expr1: number = 10 + 5 * 2;
const expr2: number = (10 + 5) * 2;
console.log(`\n【运算优先级】10 + 5 * 2 = ${expr1}`); // 20(先乘后加)
console.log(`【运算优先级】(10 + 5) * 2 = ${expr2}`); // 30(括号优先)
// 示例2:比较+逻辑运算符优先级
const x: number = 8;
const expr3: boolean = x > 5 && x < 10;
console.log(`【运算优先级】x > 5 && x < 10 = ${expr3}`); // true
// 示例3:三元+赋值运算符优先级
let y: number = 0;
y = x > 5 ? 10 : 5; // 三元优先级高于赋值
console.log(`【运算优先级】y = x > 5 ? 10 : 5 → ${y}`); // 10
// 示例4:逻辑非+比较运算符优先级
const expr5: boolean = !(10 > 5 && 3 < 2); // 括号改变顺序
console.log(`【运算优先级】!(10 > 5 && 3 < 2) = ${expr5}`); // true
}
/**
* 思考题:浮点数精度问题
*/
export function floatPrecisionIssue(): void {
const num3: number = 0.2 + 0.1;
console.log(`\n【思考题】0.2 + 0.1 = ${num3}`); // 输出:0.30000000000000004
console.log(`【思考题说明】浮点数在二进制存储中存在精度损耗,下节将学习如何控制数值精度`);
}
7.3 运行效果
【运算优先级】10 + 5 * 2 = 20
【运算优先级】(10 + 5) * 2 = 30
【运算优先级】x > 5 && x < 10 = true
【运算优先级】x > (5 && x) < 10 = false
【运算优先级】y = x > 5 ? 10 : 5 → 10
【运算优先级】!(10 > 5 && 3 < 2) = true
【运算优先级】!10 > 5 && 3 < 2 = false
【思考题】0.2 + 0.1 = 0.30000000000000004
【思考题说明】浮点数在二进制存储中存在精度损耗,下节将学习如何控制数值精度
八、完整页面调用代码(Index.ets)
// src/main/ets/pages/Index.ets
import {
arithmeticOperators,
assignmentOperators,
comparisonAndTypeofOperators,
logicalOperators,
ternaryOperators,
operatorPrecedence,
floatPrecisionIssue
} from '../utils/OperatorTest';
@Entry
@Component
struct Index {
// 组件渲染前调用所有测试函数
aboutToAppear(): void {
// 1. 算术运算符
arithmeticOperators();
// 2. 赋值运算符
assignmentOperators();
// 3. 比较与typeof运算符
comparisonAndTypeofOperators();
// 4. 逻辑运算符
logicalOperators();
// 5. 三元运算符
ternaryOperators();
// 6. 运算优先级
operatorPrecedence();
// 7. 浮点数精度思考题
floatPrecisionIssue();
}
build() {
Column() {
Text("ArkTS核心运算符与运算规则")
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center);
}
}
九、核心开发规范与注意事项
- 相等性判断:优先使用
===/!==,避免==/!=的类型转换陷阱; - || 与 ?? 选择:需要保留0、""、false等有效假值时用
??,过滤所有假值时用||; - 自增/自减:尽量单独使用,避免嵌入复杂表达式,提升可读性;
- 复杂表达式:必须用括号
()明确执行顺序,不要依赖优先级记忆; - 类型转换:字符串拼接时,number转string建议显式调用
toString(),避免隐式转换; - typeof注意:
typeof null返回object是历史遗留问题,需特殊处理。
十、内容总结
- 核心运算符:掌握算术(含自增自减)、赋值、比较、逻辑(含
??)、三元运算符的用法,以及typeof的类型检测功能; - 避坑要点:
==(仅比数值)vs===(比数值+类型):优先用===;||(判断假值)vs??(判断空值):根据是否保留0/""选择使用;
- 关键特性:逻辑运算符的短路特性可简化代码,括号
()拥有最高运算优先级,浮点数存在二进制精度损耗问题; - 强类型适配:运算符操作需遵循类型一致性,显式转换类型避免隐式转换问题。
十一、代码仓库
- 工程名称:OperatorDemo
- 仓库地址:https://gitee.com/juhetianxia321/harmony-os-code-base.git
十二、下节预告
下一节学习基础数据类型的包装对象与类型转换,重点包括:
- 掌握
Number、String、Boolean包装对象的核心特性与高频内置方法; - 熟练处理
null、undefined的边界场景,掌握显式类型转换技巧; - 解决浮点数精度问题,完成数值计算、文本处理的基础开发需求。
浙公网安备 33010602011771号