【应用开发】HarmonyOS6应用系统基于ArkTS编程语言的应用程序开发指南

admin 2026-03-03 05:02:21 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档为HarmonyOS6应用开发指南,聚焦ArkTS编程语言的应用实践。内容涵盖HarmonyOSNEXT架构特点、Kit开放能力分类、DevEcoStudio工程构建流程及Stage模型目录结构。文档详细阐述了ArkTS语言的设计理念与核心优势,并深入解析了变量声明、数据类型、运算符及控制流语句等编程语法,为开发者构建高性能移动应用提供了系统性的技术参考与操作指引。 综合评分: 80 文章分类: 安全开发,移动安全,应用安全


cover_image

【应用开发】HarmonyOS 6 应用系统基于ArkTS编程语言的应用程序开发指南

原创

利刃信安 利刃信安

利刃信安

2026年2月26日 16:02 北京

HarmonyOS 6 应用系统基于ArkTS编程语言的应用程序开发指南


第1章 概述

HarmonyOS是新一代的智能终端操作系统,为不同设备的智能化、互联与协同提供了统一的语言。2024年HarmonyOS以全新架构发布,命名为HarmonyOS NEXT。HarmonyOS NEXT于2024年6月21日公开发布首个Developer Beta版本,并于2024年10月22日正式公开发布首个Release版本(版本号5.0.0)。HarmonyOS NEXT采用OpenHarmony作为操作系统底座,并通过OpenHarmony兼容性标准认证。

本指南旨在帮助开发者全面了解HarmonyOS应用开发,掌握ArkTS编程语言的核心功能、语法、规范和最佳实践,助力开发者高效构建高性能的移动应用。

1.1 应用开发文档结构

应用开发文档包含以下主要内容:

| 模块 | 说明 | | — | — | | 入门 | 帮助开发者了解应用开发的基本方法,快速构建首个HarmonyOS应用 | | 开发 | 从HarmonyOS NEXT Developer Preview1(API 11)版本开始,HarmonyOS SDK以Kit维度提供丰富、完备的开放能力 | | 工具 | DevEco Studio工具的详细用法,包括工程创建、应用签名、应用调试、应用安装运行 | | API参考 | HarmonyOS SDK各Kit开放能力的全量组件和接口说明文档 |

1.2 Kit开放能力分类

HarmonyOS SDK以Kit维度提供开放能力,涵盖六大领域:

| 领域 | Kit示例 | | — | — | | 应用框架 | Ability Kit(程序框架服务)、ArkUI(方舟UI框架)等 | | 系统 | Universal Keystore Kit(密钥管理服务)、Network Kit(网络服务)等 | | 媒体 | Audio Kit(音频服务)、Media Library Kit(媒体文件管理服务)等 | | 图形 | ArkGraphics 2D(方舟2D图形服务)、Graphics Accelerate Kit(图形加速服务)等 | | 应用服务 | Game Service Kit(游戏服务)、Location Kit(位置服务)等 | | AI | Intents Kit(意图框架服务)、CANN Kit(CANN服务)等 |


第2章 HarmonyOS应用开发基础

2.1 创建第一个应用

2.1.1 工程创建步骤

  1. 1. 启动DevEco Studio
  • • 首次打开:单击 Create Project 创建工程
  • • 已有工程:选择 File > New > Create Project 创建新工程
  1. 2. 选择模板
  • • 选择 Application 应用开发(Atomic Service对应为元服务开发)
  • • 选择 Empty Ability 模板
  • • 如需Native开发,选择 Native C++ 模板
  1. 3. 配置工程
  • • 设置 Compatible SDK(兼容的最低API Version)
  • • 其他参数保持默认设置

2.2 ArkTS工程目录结构(Stage模型)

项目根目录/
├── AppScope/
│   └── app.json5                    # 应用的全局配置信息
├── entry/                           # HarmonyOS工程模块,编译构建生成HAP包
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/                 # ArkTS源码目录
│   │   │   │   ├── entryability/    # 应用/服务的入口
│   │   │   │   ├── entrybackupability/  # 应用扩展的备份恢复能力
│   │   │   │   └── pages/           # 应用/服务包含的页面
│   │   │   ├── resources/           # 资源文件(图形、多媒体、字符串、布局等)
│   │   │   └── module.json5         # 模块配置文件
│   │   └── ohosTest/                # 测试代码目录
│   ├── build-profile.json5          # 模块信息、编译信息配置
│   ├── hvigorfile.ts                # 模块级编译构建任务脚本
│   ├── obfuscation-rules.txt        # 混淆规则文件
│   └── oh-package.json5             # 包名、版本、入口文件和依赖项信息
├── oh_modules/                      # 三方库依赖信息
├── build-profile.json5              # 工程级配置信息(签名、产品配置等)
├── hvigorfile.ts                    # 工程级编译构建任务脚本
└── oh-package.json5                 # 全局配置(依赖覆盖、依赖关系重写等)

2.3 构建应用页面

2.3.1 第一个页面示例

@Entry
@Component
struct Index {
  build() {
    Column() {
      Text('第一个页面')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      Button('跳转到第二页')
        .margin({ top: 20 })
        .onClick(() => {
          router.pushUrl({ url: 'pages/Second' })
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

2.3.2 配置页面路由

在 main_pages.json 文件中配置:

{
  "src": [
    "pages/Index",
    "pages/Second"
  ]
}

2.3.3 页面跳转实现

import router from '@ohos.router'

// 跳转到第二个页面
router.pushUrl({ url: 'pages/Second' })

// 返回上一个页面
router.back()

第3章 ArkTS编程语言介绍

3.1 语言概述

ArkTS是一种设计用于构建高性能应用的编程语言。它在继承TypeScript语法的基础上进行了优化,以提供更高的性能和开发效率。

许多编程语言在设计之初未考虑移动设备,导致应用运行缓慢、低效且功耗大。随着移动设备在日常生活中越来越普遍,针对移动环境的编程语言优化需求日益增加。ArkTS专为解决这些问题而设计,聚焦提高运行效率。

TypeScript是在JavaScript基础上通过添加类型定义扩展而来的,ArkTS则是TypeScript的进一步扩展。ArkTS保持了TypeScript的大部分语法,旨在为现有的TypeScript开发者提供高度兼容的体验,帮助移动开发者快速上手。

3.2 设计理念

| 特性 | 说明 | | — | — | | 高性能 | 专为移动环境优化,解决传统语言运行缓慢、低效、功耗大的问题 | | TypeScript兼容 | 保持TypeScript大部分语法,提供高度兼容的开发体验 | | 低运行时开销 | 对动态类型特性施加更严格的限制,减少运行时开销 | | 互通性 | 与TypeScript和JavaScript无缝互通,可重用现有代码和库 |

3.3 语言优势

  1. 1. 更快的应用启动:通过运行前编译和优化实现
  2. 2. 更低的功耗:针对移动设备优化
  3. 3. 高效的执行:取消动态类型特性,提高执行效率
  4. 4. 代码复用:与TypeScript/JavaScript无缝集成

第4章 ArkTS编程语法详解

4.1 声明

4.1.1 变量声明

使用关键字 let 声明的变量可以在程序执行期间具有不同的值:

let count: number = 0
count = 1

4.1.2 常量声明

使用关键字 const 声明的常量为只读类型,只能被赋值一次。对常量重新赋值会造成编译时错误:

const MAX_SIZE: number = 100

4.1.3 自动类型推断

如果变量或常量的声明包含初始值,开发者无需显式指定类型,因为ArkTS规范已列举了所有允许自动推断类型的场景:

let name = 'HarmonyOS'  // 自动推断为string类型
const version = '6.0'   // 自动推断为string类型

4.2 数据类型

4.2.1 基本类型和引用类型

基本数据类型包括number、string等简单类型,它们可以准确地表示单一的数据类型。对基本类型的存储和访问都是直接的,比较时直接比较其值。

引用类型包括对象、数组和函数等复杂数据结构。这些类型通过引用访问数据,对象和数组可以包含多个值或键值对,函数则可以封装可执行的代码逻辑。引用类型在内存中通过指针访问数据,修改引用会影响原始数据。

4.2.2 number类型

ArkTS提供number类型,任何整数和浮点数都可以被赋给此类型的变量。

整数字面量:

| 类型 | 格式 | 示例 | | — | — | — | | 十进制 | 数字序列 | 0117-345 | | 十六进制 | 0x 或 0X 开头 | 0x11230x00111-0xF1A7 | | 八进制 | 0o 或 0O 开头 | 0o777 | | 二进制 | 0b 或 0B 开头 | 0b110b0011-0b11 |

浮点数字面量:

let decimal: number = 3.14
let scientific: number = 1.5e3  // 科学计数法

大整数处理:

number类型在表示大整数(即超过-9007199254740991~9007199254740991)时会造成精度丢失。在开发时可以按需使用BigInt类型来确保精度:

let bigNumber: bigint = 9007199254740992n

4.2.3 boolean类型

boolean类型由true和false两个逻辑值组成,通常在条件语句中使用:

let isActive: boolean = true
let isCompleted: boolean = false

if (isActive) {
  console.log('状态激活')
}

4.2.4 string类型

string类型代表字符序列,可以使用转义字符来表示字符。字符串字面量由单引号(’)或双引号(”)之间括起来的零个或多个字符组成。字符串字面量还有一特殊形式,是用反向单引号(`)括起来的模板字面量:

let single: string = 'Hello'
let double: string = "World"
let template: string = `Hello, ${single} ${double}`
let escaped: string = 'Line1\nLine2'

4.2.5 void类型

void类型用于指定函数没有返回值。此类型只有一个值,同样是void。由于void是引用类型,因此它可以用于泛型类型参数:

function logMessage(message: string): void {
  console.log(message)
}

4.2.6 Object类型

Object类型是所有引用类型的基类型。任何值,包括基本类型的值,都可以直接被赋给Object类型的变量(基本类型值会被自动装箱)。object类型用于表示除基本类型外的类型:

let obj: Object = { name: 'HarmonyOS' }

4.2.7 array类型(数组)

array类型,即数组,是由可赋值给数组声明中指定的元素类型的数据组成的对象。数组可由数组复合字面量赋值:

let numbers: number[] = [1, 2, 3, 4, 5]
let&nbsp;strings:&nbsp;Array<string> = ['a',&nbsp;'b',&nbsp;'c']

4.2.8 enum类型(枚举)

enum类型,即枚举类型,是预先定义的一组命名值的值类型,其中命名值又称为枚举常量。使用枚举常量时必须以枚举类型名称为前缀:

enum&nbsp;Direction&nbsp;{
&nbsp;&nbsp;Up&nbsp;=&nbsp;'UP',
&nbsp;&nbsp;Down&nbsp;=&nbsp;'DOWN',
&nbsp;&nbsp;Left&nbsp;=&nbsp;'LEFT',
&nbsp;&nbsp;Right&nbsp;=&nbsp;'RIGHT'
}

let&nbsp;move:&nbsp;Direction&nbsp;=&nbsp;Direction.Up

常量表达式用于显式设置枚举常量的值:

enum&nbsp;HttpStatus&nbsp;{
&nbsp;&nbsp;OK&nbsp;=&nbsp;200,
&nbsp;&nbsp;NOT_FOUND&nbsp;=&nbsp;404,
&nbsp;&nbsp;INTERNAL_ERROR&nbsp;=&nbsp;500
}

4.2.9 Union类型(联合类型)

Union类型,即联合类型,是由多个类型组合成的引用类型。联合类型包含了变量可能的所有类型:

let&nbsp;value:&nbsp;string&nbsp;|&nbsp;number
value =&nbsp;'hello'
value =&nbsp;42

可以使用不同机制获取联合类型中的特定类型值:

function&nbsp;process(value:&nbsp;string&nbsp;|&nbsp;number) {
&nbsp;&nbsp;if&nbsp;(typeof&nbsp;value ===&nbsp;'string') {
&nbsp; &nbsp;&nbsp;console.log(value.toUpperCase())
&nbsp; }&nbsp;else&nbsp;{
&nbsp; &nbsp;&nbsp;console.log(value.toFixed(2))
&nbsp; }
}

4.2.10 Aliases类型(类型别名)

Aliases类型为匿名类型(如数组、函数、对象字面量或联合类型)提供名称,或为已定义的类型提供替代名称:

type&nbsp;StringOrNumber&nbsp;=&nbsp;string&nbsp;|&nbsp;number
type&nbsp;Point&nbsp;= {&nbsp;x:&nbsp;number,&nbsp;y:&nbsp;number&nbsp;}
type&nbsp;Callback&nbsp;=&nbsp;(data:&nbsp;string) =>&nbsp;void

4.3 运算符与表达式

4.3.1 赋值运算符

赋值运算符 =,使用方式如 x = y

复合赋值运算符将赋值与运算符组合在一起,例如:a += b 等价于 a = a + b

复合赋值运算符包括:+=-=*=/=%=<<=>>=>>>=&=|=^=

4.3.2 比较运算符

| 运算符 | 说明 | | — | — | | === | 如果两个操作数严格相等(对于不同类型的操作数认为是不相等的),则返回true | | !== | 如果两个操作数严格不相等,则返回true | | == | 如果两个操作数相等,则返回true | | != | 如果两个操作数不相等,则返回true | | > | 如果左操作数大于右操作数,则返回true | | >= | 如果左操作数大于或等于右操作数,则返回true | | < | 如果左操作数小于右操作数,则返回true | | <= | 如果左操作数小于或等于右操作数,则返回true |

=====的区别: === 是严格相等,对于不同类型的操作数认为是不相等的;== 会进行类型转换后比较。

4.3.3 算术运算符

一元运算符包括:-+--++

二元运算符:

| 运算符 | 说明 | | — | — | | + | 加法 | | - | 减法 | | * | 乘法 | | / | 除法 | | % | 除法后余数 |

4.3.4 位运算符

| 运算符 | 说明 | | — | — | | a & b | 按位与:如果两个操作数的对应位都为1,则将这个位设置为1,否则设置为0 | | a | b | 按位或:如果两个操作数的相应位中至少有一个为1,则将这个位设置为1,否则设置为0 | | a ^ b | 按位异或:如果两个操作数的对应位不同,则将这个位设置为1,否则设置为0 | | ~ a | 按位非:反转操作数的位 | | a << b | 左移:将a的二进制表示向左移b位 | | a >> b | 算术右移:将a的二进制表示向右移b位,带符号扩展 | | a >>> b | 逻辑右移:将a的二进制表示向右移b位,左边补0 |

4.3.5 逻辑运算符

| 运算符 | 说明 | | — | — | | a && b | 逻辑与 | | a || b | 逻辑或 | | ! a | 逻辑非 |

4.3.6 instanceof运算符

instanceof运算符用于在运行时检查一个对象是否是指定类或其子类的实例:

class&nbsp;Animal&nbsp;{}
class&nbsp;Dog&nbsp;extends&nbsp;Animal&nbsp;{}

let&nbsp;dog =&nbsp;new&nbsp;Dog()
console.log(dog&nbsp;instanceof&nbsp;Dog) &nbsp; &nbsp;// true
console.log(dog&nbsp;instanceof&nbsp;Animal)&nbsp;// true

返回值类型为boolean。如果obj是className类或其子类的实例,则返回值为true;否则,返回值为false。

4.4 控制流语句

4.4.1 if语句

if语句用于需要根据逻辑条件执行不同语句的场景。当逻辑条件为真时,执行对应的一组语句,否则执行另一组语句(如果有的话):

if&nbsp;(condition) {
&nbsp;&nbsp;// 条件为真时执行
}&nbsp;else&nbsp;if&nbsp;(anotherCondition) {
&nbsp;&nbsp;// 另一个条件为真时执行
}&nbsp;else&nbsp;{
&nbsp;&nbsp;// 所有条件都不满足时执行
}

条件表达式可以是任何类型,非boolean类型会进行隐式类型转换。

4.4.2 switch语句

使用switch语句执行与switch表达式值匹配的代码块:

switch&nbsp;(value) {
&nbsp;&nbsp;case&nbsp;1:
&nbsp; &nbsp;&nbsp;console.log('值为1')
&nbsp; &nbsp;&nbsp;break
&nbsp;&nbsp;case&nbsp;2:
&nbsp; &nbsp;&nbsp;console.log('值为2')
&nbsp; &nbsp;&nbsp;break
&nbsp;&nbsp;default:
&nbsp; &nbsp;&nbsp;console.log('其他值')
&nbsp; &nbsp;&nbsp;break
}

如果switch表达式的值等于某个label的值,则执行相应的语句。如果没有任何一个label值与表达式值相匹配,并且switch具有default子句,那么程序会执行default子句对应的代码块。

break语句(可选的)允许跳出switch语句并继续执行switch语句之后的语句。如果没有break语句,则执行switch中的下一个label对应的代码块。

4.4.3 条件表达式(三元运算符)

条件表达式根据第一个表达式的布尔值来返回其他两个表达式之一的结果:

let&nbsp;result = condition ? expression1 : expression2

如果condition的值为真值(转换后为true的值),则使用expression1作为该表达式的结果;否则,使用expression2作为该表达式的结果。

let&nbsp;age =&nbsp;18
let&nbsp;status = age >=&nbsp;18&nbsp;?&nbsp;'成年'&nbsp;:&nbsp;'未成年'

4.4.4 for语句

for语句会被重复执行,直到循环退出语句值为false:

for&nbsp;(let&nbsp;i =&nbsp;0; i <&nbsp;10; i++) {
&nbsp;&nbsp;console.log(i)
}

for语句的执行流程如下:

  1. 1. 执行init表达式(如有)。此表达式通常初始化一个或多个循环计数器。
  2. 2. 计算condition。如果它为真值,则执行循环主体的语句。如果它为假值,则for循环终止。
  3. 3. 执行循环主体的语句。
  4. 4. 如果有update表达式,则执行该表达式。
  5. 5. 返回步骤2。

4.4.5 for-of语句

使用for-of语句可遍历数组、Set、Map、字符串等可迭代的类型:

let&nbsp;array = [1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5]
for&nbsp;(let&nbsp;item&nbsp;of&nbsp;array) {
&nbsp;&nbsp;console.log(item)
}

4.4.6 while语句

只要condition为真值,while语句就会执行statements语句:

let&nbsp;count =&nbsp;0
while&nbsp;(count <&nbsp;10) {
&nbsp;&nbsp;console.log(count)
&nbsp; count++
}

4.4.7 do-while语句

如果condition的值为真值,那么statements语句会重复执行:

let&nbsp;count =&nbsp;0
do&nbsp;{
&nbsp;&nbsp;console.log(count)
&nbsp; count++
}&nbsp;while&nbsp;(count <&nbsp;10)

4.4.8 break语句

使用break语句可以终止循环语句或switch:

for&nbsp;(let&nbsp;i =&nbsp;0; i <&nbsp;10; i++) {
&nbsp;&nbsp;if&nbsp;(i ===&nbsp;5) {
&nbsp; &nbsp;&nbsp;break&nbsp;&nbsp;// 终止循环
&nbsp; }
&nbsp;&nbsp;console.log(i)
}

如果break语句后带有标识符,则将控制流转移到该标识符所包含的语句块之外。

4.4.9 continue语句

continue语句会停止当前循环迭代的执行,并将控制传递给下一次迭代:

for&nbsp;(let&nbsp;i =&nbsp;0; i <&nbsp;10; i++) {
&nbsp;&nbsp;if&nbsp;(i ===&nbsp;5) {
&nbsp; &nbsp;&nbsp;continue&nbsp;&nbsp;// 跳过本次迭代
&nbsp; }
&nbsp;&nbsp;console.log(i)
}

4.4.10 throw和try语句

throw语句用于抛出异常或错误:

throw&nbsp;new&nbsp;Error('发生错误')

try语句用于捕获和处理异常或错误,支持finally语句:

try&nbsp;{
&nbsp;&nbsp;// 可能抛出异常的代码
}&nbsp;catch&nbsp;(e) {
&nbsp;&nbsp;// 处理异常
}&nbsp;finally&nbsp;{
&nbsp;&nbsp;// 无论是否发生异常都会执行
}

下面的示例中throw和try语句用于处理除数为0的错误:

function&nbsp;divide(a:&nbsp;number,&nbsp;b:&nbsp;number):&nbsp;number&nbsp;{
&nbsp;&nbsp;if&nbsp;(b ===&nbsp;0) {
&nbsp; &nbsp;&nbsp;throw&nbsp;new&nbsp;Error('除数不能为0')
&nbsp; }
&nbsp;&nbsp;return&nbsp;a / b
}

try&nbsp;{
&nbsp;&nbsp;let&nbsp;result =&nbsp;divide(10,&nbsp;0)
}&nbsp;catch&nbsp;(e) {
&nbsp;&nbsp;console.log(e.message)
}&nbsp;finally&nbsp;{
&nbsp;&nbsp;console.log('计算完成')
}

4.5 函数

4.5.1 函数声明

函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体:

function&nbsp;add(x:&nbsp;string,&nbsp;y:&nbsp;string):&nbsp;string&nbsp;{
&nbsp;&nbsp;return&nbsp;x + y
}

在函数声明中,必须为每个参数标记类型。如果参数为可选参数,那么允许在调用函数时省略该参数。函数的最后一个参数可以是rest参数。

4.5.2 可选参数

可选参数的格式可为 name?: Type

function&nbsp;greet(name:&nbsp;string,&nbsp;greeting?:&nbsp;string):&nbsp;string&nbsp;{
&nbsp;&nbsp;if&nbsp;(greeting) {
&nbsp; &nbsp;&nbsp;return&nbsp;`${greeting},&nbsp;${name}!`
&nbsp; }
&nbsp;&nbsp;return&nbsp;`Hello,&nbsp;${name}!`
}

可选参数的另一种形式为设置的参数默认值。如果在函数调用中这个参数被省略了,则会使用此参数的默认值作为实参:

function&nbsp;greet(name:&nbsp;string,&nbsp;greeting:&nbsp;string&nbsp;=&nbsp;'Hello'):&nbsp;string&nbsp;{
&nbsp;&nbsp;return&nbsp;`${greeting},&nbsp;${name}!`
}

4.5.3 rest参数

函数的最后一个参数可以是rest参数,格式为 ...restName: Type[]。rest参数允许函数接收一个不定长数组,用于处理不定数量的参数输入:

function&nbsp;sum(...numbers:&nbsp;number[]):&nbsp;number&nbsp;{
&nbsp;&nbsp;let&nbsp;total =&nbsp;0
&nbsp;&nbsp;for&nbsp;(let&nbsp;num&nbsp;of&nbsp;numbers) {
&nbsp; &nbsp; total += num
&nbsp; }
&nbsp;&nbsp;return&nbsp;total
}

sum(1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5) &nbsp;// 15

4.5.4 返回类型

如果可以从函数体内推断出函数返回类型,则可在函数声明中省略标注返回类型。不需要返回值的函数的返回类型可以显式指定为void或省略标注:

function&nbsp;logMessage(message:&nbsp;string) {
&nbsp;&nbsp;console.log(message)
}

4.5.5 函数的作用域

函数中定义的变量和其他实例仅可以在函数内部访问,不能从外部访问。如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。

4.5.6 箭头函数(Lambda函数)

函数可以定义为箭头函数:

const&nbsp;multiply = (a:&nbsp;number,&nbsp;b:&nbsp;number):&nbsp;number&nbsp;=>&nbsp;a * b

箭头函数的返回类型可以省略,此时返回类型从函数体推断。表达式可以指定为箭头函数,使表达更简短:

let&nbsp;numbers = [1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5]
let&nbsp;doubled = numbers.map(n&nbsp;=>&nbsp;n *&nbsp;2)

4.5.7 闭包

闭包是由函数及声明该函数的环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量:

function&nbsp;createCounter():&nbsp;() =>&nbsp;number&nbsp;{
&nbsp;&nbsp;let&nbsp;count =&nbsp;0
&nbsp;&nbsp;return&nbsp;() =>&nbsp;{
&nbsp; &nbsp; count++
&nbsp; &nbsp;&nbsp;return&nbsp;count
&nbsp; }
}

let&nbsp;counter =&nbsp;createCounter()
console.log(counter()) &nbsp;// 1
console.log(counter()) &nbsp;// 2

4.5.8 函数重载

可以通过编写重载,指定函数的不同调用方式。具体方法是,为同一个函数写入多个同名但签名不同的函数头,函数实现紧随其后:

function&nbsp;process(value:&nbsp;string):&nbsp;string
function&nbsp;process(value:&nbsp;number):&nbsp;number
function&nbsp;process(value:&nbsp;string&nbsp;|&nbsp;number):&nbsp;string&nbsp;|&nbsp;number&nbsp;{
&nbsp;&nbsp;if&nbsp;(typeof&nbsp;value ===&nbsp;'string') {
&nbsp; &nbsp;&nbsp;return&nbsp;value.toUpperCase()
&nbsp; }
&nbsp;&nbsp;return&nbsp;value *&nbsp;2
}

不允许重载函数有相同的参数列表,否则将导致编译错误。

4.6 类与对象

4.6.1 类声明

类声明引入一个新类型,并定义其字段、方法和构造函数:

class&nbsp;Person&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
&nbsp;&nbsp;surname:&nbsp;string

&nbsp;&nbsp;constructor(name:&nbsp;string,&nbsp;surname:&nbsp;string) {
&nbsp; &nbsp;&nbsp;this.name&nbsp;= name
&nbsp; &nbsp;&nbsp;this.surname&nbsp;= surname
&nbsp; }

&nbsp;&nbsp;fullName():&nbsp;string&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;this.name&nbsp;+&nbsp;' '&nbsp;+&nbsp;this.surname
&nbsp; }
}

定义类后,可以使用关键字new创建实例:

let&nbsp;person =&nbsp;new&nbsp;Person('John',&nbsp;'Doe')

或者,可以使用对象字面量创建实例:

let&nbsp;person:&nbsp;Person&nbsp;= {
&nbsp;&nbsp;name:&nbsp;'John',
&nbsp;&nbsp;surname:&nbsp;'Doe',
&nbsp;&nbsp;fullName:&nbsp;function() {
&nbsp; &nbsp;&nbsp;return&nbsp;this.name&nbsp;+&nbsp;' '&nbsp;+&nbsp;this.surname
&nbsp; }
}

4.6.2 字段

字段是直接在类中声明的某种类型的变量。类可以具有实例字段或者静态字段。

实例字段:

实例字段存在于类的每个实例上。每个实例都有自己的实例字段集合。要访问实例字段,需要使用类的实例:

class&nbsp;Person&nbsp;{
&nbsp;&nbsp;name:&nbsp;string&nbsp;=&nbsp;''
&nbsp;&nbsp;age:&nbsp;number&nbsp;=&nbsp;0
}

let&nbsp;person =&nbsp;new&nbsp;Person()
person.name&nbsp;=&nbsp;'John'

静态字段:

使用关键字static将字段声明为静态。静态字段属于类本身,类的所有实例共享一个静态字段。要访问静态字段,需要使用类名:

class&nbsp;Counter&nbsp;{
&nbsp;&nbsp;static&nbsp;count:&nbsp;number&nbsp;=&nbsp;0

&nbsp;&nbsp;increment():&nbsp;void&nbsp;{
&nbsp; &nbsp;&nbsp;Counter.count++
&nbsp; }
}

console.log(Counter.count)

字段初始化:

为了减少运行时错误并提升执行性能,ArkTS要求所有字段在声明时或构造函数中显式初始化,与标准TS的strictPropertyInitialization模式相同。

4.6.3 getter和setter

setter和getter可用于提供对类属性的受控访问:

class&nbsp;Person&nbsp;{
&nbsp;&nbsp;private&nbsp;_age:&nbsp;number&nbsp;=&nbsp;0

&nbsp;&nbsp;get&nbsp;age():&nbsp;number&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;this._age
&nbsp; }

&nbsp;&nbsp;set&nbsp;age(value:&nbsp;number) {
&nbsp; &nbsp;&nbsp;if&nbsp;(value >=&nbsp;0) {
&nbsp; &nbsp; &nbsp;&nbsp;this._age&nbsp;= value
&nbsp; &nbsp; }
&nbsp; }
}

4.6.4 方法

方法属于类。类可以定义实例方法或者静态方法。静态方法属于类本身,只能访问静态字段。而实例方法既可以访问静态字段,也可以访问实例字段,包括类的私有字段。

实例方法:

class&nbsp;Rectangle&nbsp;{
&nbsp;&nbsp;width:&nbsp;number&nbsp;=&nbsp;0
&nbsp;&nbsp;height:&nbsp;number&nbsp;=&nbsp;0

&nbsp;&nbsp;calculateArea():&nbsp;number&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;this.width&nbsp;*&nbsp;this.height
&nbsp; }
}

let&nbsp;rect =&nbsp;new&nbsp;Rectangle()
rect.width&nbsp;=&nbsp;10
rect.height&nbsp;=&nbsp;20
let&nbsp;area = rect.calculateArea()

静态方法:

使用关键字static声明静态方法。静态方法属于类,只能访问静态字段:

class&nbsp;MathUtils&nbsp;{
&nbsp;&nbsp;static&nbsp;PI:&nbsp;number&nbsp;=&nbsp;3.14159

&nbsp;&nbsp;static&nbsp;calculateCircleArea(radius:&nbsp;number):&nbsp;number&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;MathUtils.PI&nbsp;* radius * radius
&nbsp; }
}

let&nbsp;area =&nbsp;MathUtils.calculateCircleArea(5)

4.6.5 继承

一个类可以继承另一个类(称为基类),并使用以下语法实现多个接口:

class&nbsp;Student&nbsp;extends&nbsp;Person&nbsp;implements&nbsp;IStudent&nbsp;{
&nbsp;&nbsp;school:&nbsp;string&nbsp;=&nbsp;''

&nbsp;&nbsp;constructor(name:&nbsp;string,&nbsp;surname:&nbsp;string,&nbsp;school:&nbsp;string) {
&nbsp; &nbsp;&nbsp;super(name, surname)
&nbsp; &nbsp;&nbsp;this.school&nbsp;= school
&nbsp; }

&nbsp;&nbsp;fullName():&nbsp;string&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;super.fullName() +&nbsp;', school: '&nbsp;+&nbsp;this.school
&nbsp; }
}

继承类继承基类的字段和方法,但不继承构造函数。继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。

4.6.6 方法重写

子类可以重写其父类中定义的方法的实现。重写的方法必须具有与原始方法相同的参数类型和相同或派生的返回类型:

class&nbsp;Animal&nbsp;{
&nbsp;&nbsp;speak():&nbsp;string&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;'Some sound'
&nbsp; }
}

class&nbsp;Dog&nbsp;extends&nbsp;Animal&nbsp;{
&nbsp;&nbsp;speak():&nbsp;string&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;'Woof'
&nbsp; }
}

4.6.7 方法重载签名

通过重载签名,指定方法的不同调用:

class&nbsp;Calculator&nbsp;{
&nbsp;&nbsp;add(a:&nbsp;number,&nbsp;b:&nbsp;number):&nbsp;number
&nbsp;&nbsp;add(a:&nbsp;string,&nbsp;b:&nbsp;string):&nbsp;string
&nbsp;&nbsp;add(a:&nbsp;number&nbsp;|&nbsp;string,&nbsp;b:&nbsp;number&nbsp;|&nbsp;string):&nbsp;number&nbsp;|&nbsp;string&nbsp;{
&nbsp; &nbsp;&nbsp;if&nbsp;(typeof&nbsp;a ===&nbsp;'number'&nbsp;&&&nbsp;typeof&nbsp;b ===&nbsp;'number') {
&nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;a + b
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;return&nbsp;String(a) +&nbsp;String(b)
&nbsp; }
}

4.6.8 构造函数

类声明可以包含用于初始化对象状态的构造函数:

class&nbsp;Person&nbsp;{
&nbsp;&nbsp;name:&nbsp;string

&nbsp;&nbsp;constructor(name:&nbsp;string) {
&nbsp; &nbsp;&nbsp;this.name&nbsp;= name
&nbsp; }
}

如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数。在这种情况下,默认构造函数使用字段类型的默认值初始化实例中的字段。

派生类的构造函数:

构造函数函数体的第一条语句可以使用关键字super来显式调用直接父类的构造函数:

class&nbsp;Student&nbsp;extends&nbsp;Person&nbsp;{
&nbsp;&nbsp;school:&nbsp;string

&nbsp;&nbsp;constructor(name:&nbsp;string,&nbsp;school:&nbsp;string) {
&nbsp; &nbsp;&nbsp;super(name)
&nbsp; &nbsp;&nbsp;this.school&nbsp;= school
&nbsp; }
}

构造函数重载签名:

可以通过编写重载签名,指定构造函数的不同调用方式:

class&nbsp;Point&nbsp;{
&nbsp;&nbsp;x:&nbsp;number
&nbsp;&nbsp;y:&nbsp;number

&nbsp;&nbsp;constructor()
&nbsp;&nbsp;constructor(x:&nbsp;number,&nbsp;y:&nbsp;number)
&nbsp;&nbsp;constructor(x?:&nbsp;number,&nbsp;y?:&nbsp;number) {
&nbsp; &nbsp;&nbsp;this.x&nbsp;= x ??&nbsp;0
&nbsp; &nbsp;&nbsp;this.y&nbsp;= y ??&nbsp;0
&nbsp; }
}

4.6.9 可见性修饰符

类的方法和属性都可以使用可见性修饰符。可见性修饰符包括:private、protected和public。默认可见性为public。

Public(公有): public修饰的类成员(字段、方法、构造函数)在程序的任何可访问该类的地方都是可见的。

Private(私有): private修饰的成员不能在声明该成员的类之外访问:

class&nbsp;Person&nbsp;{
&nbsp;&nbsp;private&nbsp;name:&nbsp;string

&nbsp;&nbsp;constructor(name:&nbsp;string) {
&nbsp; &nbsp;&nbsp;this.name&nbsp;= name
&nbsp; }
}

Protected(受保护): protected修饰符的作用与private修饰符非常相似,不同点是protected修饰的成员允许在派生类中访问:

class&nbsp;Animal&nbsp;{
&nbsp;&nbsp;protected&nbsp;name:&nbsp;string

&nbsp;&nbsp;constructor(name:&nbsp;string) {
&nbsp; &nbsp;&nbsp;this.name&nbsp;= name
&nbsp; }
}

class&nbsp;Dog&nbsp;extends&nbsp;Animal&nbsp;{
&nbsp;&nbsp;bark():&nbsp;void&nbsp;{
&nbsp; &nbsp;&nbsp;console.log(this.name) &nbsp;// 可以访问
&nbsp; }
}

4.6.10 对象字面量

对象字面量是一个表达式,可用于创建类实例并提供一些初始值。它在某些情况下更方便,可以用来代替new表达式:

let&nbsp;person = {&nbsp;name:&nbsp;'John',&nbsp;age:&nbsp;25&nbsp;}

ArkTS是静态类型语言,对象字面量只能在可以推导出该字面量类型的上下文中使用。

Record类型的对象字面量:

泛型 Record<K, V> 用于将类型(键类型)的属性映射到另一个类型(值类型):

let&nbsp;scores:&nbsp;Record<string,&nbsp;number> = {
&nbsp;&nbsp;'John':&nbsp;95,
&nbsp;&nbsp;'Jane':&nbsp;88
}

类型K可以是字符串类型或数值类型(不包括BigInt),而V可以是任何类型。

4.6.11 抽象类

带有abstract修饰符的类称为抽象类。抽象类可用于表示一组更具体的概念所共有的概念。尝试创建抽象类的实例会导致编译错误:

abstract&nbsp;class&nbsp;Animal&nbsp;{
&nbsp;&nbsp;abstract&nbsp;speak():&nbsp;void
}

// let animal = new Animal() &nbsp;// 编译错误

抽象类的子类可以是抽象类也可以是非抽象类。抽象父类的非抽象子类可以实例化。

抽象方法:

带有abstract修饰符的方法称为抽象方法,抽象方法可以被声明但不能被实现。只有抽象类内才能有抽象方法:

abstract&nbsp;class&nbsp;Shape&nbsp;{
&nbsp;&nbsp;abstract&nbsp;getArea():&nbsp;number
}

class&nbsp;Circle&nbsp;extends&nbsp;Shape&nbsp;{
&nbsp;&nbsp;radius:&nbsp;number

&nbsp;&nbsp;constructor(radius:&nbsp;number) {
&nbsp; &nbsp;&nbsp;super()
&nbsp; &nbsp;&nbsp;this.radius&nbsp;= radius
&nbsp; }

&nbsp;&nbsp;getArea():&nbsp;number&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;Math.PI&nbsp;*&nbsp;this.radius&nbsp;*&nbsp;this.radius
&nbsp; }
}

4.7 接口

4.7.1 接口声明

接口声明引入新类型。接口是定义代码协定的常见方式。任何类的实例,只要实现了特定接口,即可通过该接口实现多态。接口通常包含属性和方法的声明:

interface&nbsp;IUserInfo&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
&nbsp;&nbsp;age:&nbsp;number
&nbsp;&nbsp;email?:&nbsp;string
}

function&nbsp;printUserInfo(user:&nbsp;IUserInfo):&nbsp;void&nbsp;{
&nbsp;&nbsp;console.log(`姓名:&nbsp;${user.name}, 年龄:&nbsp;${user.age}`)
&nbsp;&nbsp;if&nbsp;(user.email) {
&nbsp; &nbsp;&nbsp;console.log(`邮箱:&nbsp;${user.email}`)
&nbsp; }
}

4.7.2 实现接口

实现接口的类示例:

interface&nbsp;IAnimal&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
&nbsp;&nbsp;speak():&nbsp;void
}

class&nbsp;Dog&nbsp;implements&nbsp;IAnimal&nbsp;{
&nbsp;&nbsp;name:&nbsp;string&nbsp;=&nbsp;'Dog'

&nbsp;&nbsp;speak():&nbsp;void&nbsp;{
&nbsp; &nbsp;&nbsp;console.log('Woof')
&nbsp; }
}

包含implements子句的类必须实现列出的接口中定义的所有方法,但使用默认实现定义的方法除外。

4.7.3 接口属性

接口属性可以是字段、getter、setter或getter和setter组合的形式。属性字段只是getter/setter对的便捷写法:

interface&nbsp;IPoint&nbsp;{
&nbsp;&nbsp;x:&nbsp;number
&nbsp;&nbsp;y:&nbsp;number
}

4.7.4 接口继承

接口可以继承其他接口:

interface&nbsp;IAnimal&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
}

interface&nbsp;IDog&nbsp;extends&nbsp;IAnimal&nbsp;{
&nbsp;&nbsp;breed:&nbsp;string
}

继承接口包含被继承接口的所有属性和方法,还可以添加自己的属性和方法。

4.7.5 抽象类和接口的区别

抽象类与接口都无法实例化。抽象类是类的抽象,抽象类用来捕捉子类的通用特性,接口是行为的抽象。在ArkTS语法中抽象类与接口的区别如下:

| 特性 | 抽象类 | 接口 | | — | — | — | | 继承数量 | 一个类只能继承一个抽象类 | 一个类可以实现一个或多个接口 | | 静态成员 | 可以有静态代码块和静态方法 | 不能含有静态代码块以及静态方法 | | 方法实现 | 可以有方法的实现 | 没有方法的实现,是完全抽象的 | | 构造函数 | 可以有构造函数 | 不能有构造函数 |

4.8 枚举

enum类型,即枚举类型,是预先定义的一组命名值的值类型:

enum&nbsp;Direction&nbsp;{
&nbsp;&nbsp;Up&nbsp;=&nbsp;'UP',
&nbsp;&nbsp;Down&nbsp;=&nbsp;'DOWN',
&nbsp;&nbsp;Left&nbsp;=&nbsp;'LEFT',
&nbsp;&nbsp;Right&nbsp;=&nbsp;'RIGHT'
}

let&nbsp;move:&nbsp;Direction&nbsp;=&nbsp;Direction.Up

使用枚举常量时必须以枚举类型名称为前缀。常量表达式用于显式设置枚举常量的值。

4.9 泛型

泛型类型和函数使代码能够以类型安全的方式操作多种数据类型,而无需为每种类型编写重复的逻辑。

4.9.1 泛型类和接口

类和接口可以定义为泛型,将参数添加到类型定义中:

interface&nbsp;IContainer<T> {
&nbsp;&nbsp;value: T
&nbsp;&nbsp;getValue(): T
}

class&nbsp;Container<T>&nbsp;implements&nbsp;IContainer<T> {
&nbsp;&nbsp;value: T

&nbsp;&nbsp;constructor(value: T) {
&nbsp; &nbsp;&nbsp;this.value&nbsp;= value
&nbsp; }

&nbsp;&nbsp;getValue(): T {
&nbsp; &nbsp;&nbsp;return&nbsp;this.value
&nbsp; }
}

要使用类型Container,必须为每个类型参数指定类型实参:

let&nbsp;numberContainer =&nbsp;new&nbsp;Container<number>(42)
let&nbsp;stringContainer =&nbsp;new&nbsp;Container<string>('Hello')

编译器在使用泛型类型和函数时会确保类型安全。

4.9.2 泛型约束

泛型类型的类型参数可以被限制只能取某些特定的值:

interface&nbsp;IHashable&nbsp;{
&nbsp;&nbsp;hash():&nbsp;number
}

class&nbsp;HashMap<Key&nbsp;extends&nbsp;IHashable,&nbsp;Value> {
&nbsp;&nbsp;// Key类型必须具有hash方法
}

在上面的例子中,Key类型扩展了IHashable,IHashable接口的所有方法都可以为key调用。

4.9.3 泛型函数

使用泛型函数可编写更通用的代码:

function&nbsp;getLastElement<T>(array: T[]): T |&nbsp;undefined&nbsp;{
&nbsp;&nbsp;return&nbsp;array[array.length&nbsp;-&nbsp;1]
}

let&nbsp;numbers = [1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5]
let&nbsp;last =&nbsp;getLastElement(numbers)

在函数调用中,类型实参可以显式或隐式设置:

getLastElement<number>(numbers) &nbsp;// 显式
getLastElement(numbers) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 隐式推断

4.9.4 泛型默认值

泛型类型的类型参数可以设置默认值,这样无需指定实际类型实参,直接使用泛型类型名称即可:

class&nbsp;Stack<T =&nbsp;number> {
&nbsp;&nbsp;private&nbsp;items: T[] = []

&nbsp;&nbsp;push(item: T):&nbsp;void&nbsp;{
&nbsp; &nbsp;&nbsp;this.items.push(item)
&nbsp; }

&nbsp;&nbsp;pop(): T |&nbsp;undefined&nbsp;{
&nbsp; &nbsp;&nbsp;return&nbsp;this.items.pop()
&nbsp; }
}

let&nbsp;stack =&nbsp;new&nbsp;Stack() &nbsp;// T默认为number

4.10 空值安全

默认情况下,ArkTS中的所有类型都不允许为空,这类似于TypeScript的strictNullChecks模式,但规则更严格。

4.10.1 可空类型

可以为空值的变量定义为联合类型 T | null

let&nbsp;name:&nbsp;string&nbsp;|&nbsp;null&nbsp;=&nbsp;null
let&nbsp;age:&nbsp;number&nbsp;|&nbsp;undefined&nbsp;=&nbsp;undefined

4.10.2 非空断言运算符

后缀运算符 ! 可用于断言其操作数为非空。当应用于可空类型的值时,编译时类型会变为非空类型:

let&nbsp;value:&nbsp;string&nbsp;|&nbsp;null&nbsp;=&nbsp;getValue()
let&nbsp;length:&nbsp;number&nbsp;= value!.length&nbsp;&nbsp;// 确定value不为null

4.10.3 空值合并运算符

空值合并二元运算符 ?? 用于检查左侧表达式的求值是否等于null或者undefined。如果是,则表达式的结果为右侧表达式;否则,结果为左侧表达式:

let&nbsp;value:&nbsp;string&nbsp;|&nbsp;null&nbsp;=&nbsp;null
let&nbsp;result = value ??&nbsp;'default'&nbsp;&nbsp;// 如果value为null或undefined,使用默认值

换句话说,a ?? b 等价于三元运算符 (a != null && a != undefined) ? a : b

4.10.4 可选链

访问对象属性时,如果属性是undefined或null,可选链运算符返回undefined:

let&nbsp;user = {
&nbsp;&nbsp;profile: {
&nbsp; &nbsp;&nbsp;name:&nbsp;'John'
&nbsp; }
}

let&nbsp;name = user?.profile?.name&nbsp;&nbsp;// 安全访问

可选链可以任意长,可以包含任意数量的 ?. 运算符。

4.11 模块

程序可划分为多组编译单元或模块。每个模块都有其自己的作用域,即在模块中创建的任何声明(变量、函数、类等)在该模块之外都不可见,除非它们被显式导出。

4.11.1 导出

可以使用关键字export导出顶层的声明:

export&nbsp;class&nbsp;Person&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
}

export&nbsp;function&nbsp;greet(name:&nbsp;string):&nbsp;string&nbsp;{
&nbsp;&nbsp;return&nbsp;`Hello,&nbsp;${name}`
}

export&nbsp;const&nbsp;MAX_SIZE&nbsp;=&nbsp;100

未导出的声明名称被视为私有名称,只能在声明该名称的模块中使用。

导出默认导出的对象:

export&nbsp;default&nbsp;class&nbsp;Person&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
}

4.11.2 静态导入

导入声明用于导入从其他模块导出的实体,并在当前模块中提供其绑定:

// 导入所有导出
import&nbsp;*&nbsp;as&nbsp;Utils&nbsp;from&nbsp;'./utils'

// 导入特定实体
import&nbsp;{&nbsp;Person, greet }&nbsp;from&nbsp;'./utils'

// 导入并重命名
import&nbsp;{&nbsp;Person&nbsp;as&nbsp;User&nbsp;}&nbsp;from&nbsp;'./utils'

4.11.3 动态导入

在应用开发的有些场景中,如果希望根据条件导入模块或者按需导入模块,可以使用动态导入代替静态导入。import() 语法被称为动态导入,是一种类似函数的表达式,用于动态导入模块:

async&nbsp;function&nbsp;loadModule() {
&nbsp;&nbsp;const&nbsp;module&nbsp;=&nbsp;await&nbsp;import('./utils')
&nbsp;&nbsp;module.greet('World')
}

调用这种方式,会返回一个promise,该promise resolve为一个包含其所有导出的模块对象。

4.11.4 导入HarmonyOS SDK的开放能力

HarmonyOS SDK提供的开放能力(接口)也需要在导入声明后使用:

import&nbsp;router&nbsp;from&nbsp;'@ohos.router'

从HarmonyOS NEXT Developer Preview 1版本开始引入Kit概念。SDK对同一个Kit下的接口模块进行了封装,开发者在示例代码中可通过导入Kit的方式来使用Kit所包含的接口能力:

// 方式一:导入Kit下单个模块的接口能力
import&nbsp;{ router }&nbsp;from&nbsp;'@kit.ArkUI'

// 方式二:导入Kit下多个模块的接口能力
import&nbsp;{ router, alert }&nbsp;from&nbsp;'@kit.ArkUI'

// 方式三:导入Kit包含的所有模块的接口能力
import&nbsp;*&nbsp;as&nbsp;module&nbsp;from&nbsp;'@kit.ArkUI'

4.12 注解

注解(Annotation)是一种语言特性,它通过添加元数据来改变应用声明的语义。

4.12.1 注解声明和使用

使用 @interface 声明注解:

@interface&nbsp;ClassAuthor&nbsp;{
&nbsp;&nbsp;name:&nbsp;string
&nbsp;&nbsp;date:&nbsp;string
}

@ClassAuthor({&nbsp;name:&nbsp;'John',&nbsp;date:&nbsp;'2024-01-01'&nbsp;})
class&nbsp;MyClass&nbsp;{
&nbsp;&nbsp;// 类实现
}

注解必须放置在声明之前。注解可以包含参数。对于要使用的注解,其名称必须以符号 @ 为前缀。

4.12.2 注解字段类型限制

注解字段仅限于下面列举的类型:

  • • number
  • • boolean
  • • string
  • • 枚举
  • • 以上类型的数组

注解字段类型不支持BigInt。

4.12.3 注解使用限制

  • • 注解不是Typescript中的特性,只能在 .ets/.d.ets 文件中使用
  • • 当前仅允许对class declarations和method declarations使用注解
  • • 不支持对抽象类或抽象方法使用注解
  • • 子类不会继承基类的注解,也不会继承基类方法的注解

第5章 ArkTS编程规范

5.1 总体原则

规则分为两个级别:

| 级别 | 说明 | | — | — | | 要求 | 原则上应该遵从。本文所有内容目前均为针对ArkTS的要求 | | 建议 | 最佳实践,可结合实际情况考虑是否纳入 |

5.2 命名规范

5.2.1 为标识符取一个好名字

好的标识符命名应遵循以下原则:

  • • 清晰表达意图,避免使用单个字母或非标准缩写命名
  • • 使用正确的英文单词并符合英文语法,不要使用中文拼音
  • • 确保语句清晰,避免歧义

5.2.2 类名、枚举名、命名空间名

规则: 采用 UpperCamelCase 风格(首字母大写的驼峰命名法)

类名通常是名词或名词短语,例如Person、Student、Worker。不应使用动词,也应该避免类似Data、Info这样的模糊词。

class&nbsp;Person&nbsp;{}
class&nbsp;Student&nbsp;{}
enum&nbsp;Direction&nbsp;{}
namespace&nbsp;Application&nbsp;{}

5.2.3 变量名、方法名、参数名

规则: 采用 lowerCamelCase 风格(小驼峰命名法)

方法命名模式:

| 模式 | 示例 | | — | — | | load + 属性名() | loadData() | | put + 属性名() | putValue() | | is + 布尔属性名() | isValid() | | has + 名词/形容词() | hasPermission() | | 动词() | run() | | 动词 + 宾语() | readFile() |

变量名通常是名词或名词短语,采用小驼峰命名,便于理解。

let&nbsp;userName:&nbsp;string&nbsp;=&nbsp;'John'
let&nbsp;itemCount:&nbsp;number&nbsp;=&nbsp;0

function&nbsp;loadData():&nbsp;void&nbsp;{}
function&nbsp;isValid():&nbsp;boolean&nbsp;{&nbsp;return&nbsp;true&nbsp;}

5.2.4 常量名、枚举值名

规则: 采用全部大写,单词间使用下划线隔开

常量命名要尽量表达完整的语义:

const&nbsp;MAX_SIZE:&nbsp;number&nbsp;=&nbsp;100
const&nbsp;DEFAULT_TIMEOUT:&nbsp;number&nbsp;=&nbsp;30000

enum&nbsp;HttpStatus&nbsp;{
&nbsp;&nbsp;OK&nbsp;=&nbsp;200,
&nbsp;&nbsp;NOT_FOUND&nbsp;=&nbsp;404,
&nbsp;&nbsp;INTERNAL_ERROR&nbsp;=&nbsp;500
}

5.2.5 布尔变量命名

规则: 布尔型的局部变量或方法需加上表达是非意义的前缀(如 ishascanshould

当使用逻辑非运算符,并出现双重否定时,会出现理解问题,比如 !isNotError,难以理解。因此,应避免定义否定的布尔变量名。

let&nbsp;isActive:&nbsp;boolean&nbsp;=&nbsp;true
let&nbsp;hasPermission:&nbsp;boolean&nbsp;=&nbsp;false
let&nbsp;canEdit:&nbsp;boolean&nbsp;=&nbsp;true

5.3 格式规范

5.3.1 缩进

规则: 使用空格缩进,禁止使用Tab字符

  • • 大部分场景优先使用2个空格
  • • 换行导致的缩进优先使用4个空格

当前几乎所有的集成开发环境(IDE)和代码编辑器都支持配置将Tab键自动扩展为2个空格输入,应在代码编辑器中配置使用空格进行缩进。

5.3.2 行宽

规则: 行宽不超过120个字符

控制行宽可以间接引导程序员缩短函数和变量的命名,减少嵌套层数,精炼注释,从而提升代码可读性。

例外:

  • • 如果一行注释包含了超过120个字符的命令或URL,则可以保持一行
  • • 预处理的error信息在一行便于阅读和理解,即使超过120个字符

5.3.3 大括号使用

规则: 条件语句和循环语句的实现建议使用大括号

在if、for、do、while等语句的执行体加大括号 {} 是一种最佳实践,因为省略大括号可能导致错误,并且降低代码的清晰度。

if&nbsp;(condition) {
&nbsp;&nbsp;doSomething()
}

for&nbsp;(let&nbsp;i =&nbsp;0; i <&nbsp;10; i++) {
&nbsp;&nbsp;processItem(i)
}

5.3.4 Switch语句格式

规则: case 和 default 需缩进一层

switch的case和default要缩进一层(2个空格)。开关标签之后换行的语句,需再缩进一层(2个空格):

switch&nbsp;(value) {
&nbsp;&nbsp;case&nbsp;1:
&nbsp; &nbsp;&nbsp;handleCase1()
&nbsp; &nbsp;&nbsp;break
&nbsp;&nbsp;case&nbsp;2:
&nbsp; &nbsp;&nbsp;handleCase2()
&nbsp; &nbsp;&nbsp;break
&nbsp;&nbsp;default:
&nbsp; &nbsp;&nbsp;handleDefault()
&nbsp; &nbsp;&nbsp;break
}

5.3.5 表达式换行

规则: 运算符放行末,保持换行一致性

当语句过长或可读性不佳时,需要在合适的地方进行换行。换行时将操作符放在行末,表示”未结束,后续还有”,保持与常用的格式化工具的默认配置一致:

let&nbsp;result = value1 + value2 +
&nbsp; &nbsp; value3 + value4

let&nbsp;isValid = condition1 &&
&nbsp; &nbsp; condition2 &&
&nbsp; &nbsp; condition3

5.3.6 变量声明

规则: 多个变量定义和赋值语句不允许写在一行

每个语句的变量声明都应只声明一个变量。这种方式更便于添加变量声明,无需考虑将分号改为逗号,以免引入错误。此外,每个语句只声明一个变量,使用调试器逐个调试也很方便:

let&nbsp;name:&nbsp;string&nbsp;=&nbsp;'John'
let&nbsp;age:&nbsp;number&nbsp;=&nbsp;25

5.3.7 空格使用

规则: 空格应该突出关键字和重要信息,避免不必要的空格

总体建议如下:

  • • if, for, while, switch等关键字与左括号 ( 之间加空格
  • • 在函数定义和调用时,函数名称与参数列表的左括号 ( 之间不加空格
  • • 关键字else或catch与其之前的大括号 } 之间加空格
  • • 任何打开大括号 { 之前加空格(有两个例外:作为函数的第一个参数或数组中的第一个元素时,对象之前不用加空格;在模板中,不用加空格)
  • • 二元操作符前后加空格;三元操作符符号两侧均加空格
  • • 数组初始化中的逗号和函数中多个参数之间的逗号后加空格
  • • 在逗号或分号之前不加空格
  • • 数组的中括号内侧不要加空格
  • • 不要出现多个连续空格
if&nbsp;(condition) {
&nbsp;&nbsp;doSomething()
}

function&nbsp;greet(name:&nbsp;string):&nbsp;void&nbsp;{}

let&nbsp;result = a + b
let&nbsp;status = age >=&nbsp;18&nbsp;?&nbsp;'成年'&nbsp;:&nbsp;'未成年'

5.3.8 字符串使用单引号

规则: 建议字符串使用单引号

为了保持代码一致性和可读性,建议使用单引号:

let&nbsp;name =&nbsp;'John'
let&nbsp;message =&nbsp;'Hello, World!'

5.3.9 对象字面量换行

规则: 对象字面量属性超过4个,需要都换行

对象字面量的属性应保持一致的格式:要么每个属性都换行,要么所有属性都在同一行。当对象字面量的属性超过4个时,建议统一换行:

let&nbsp;config = {
&nbsp;&nbsp;name:&nbsp;'MyApp',
&nbsp;&nbsp;version:&nbsp;'1.0.0',
&nbsp;&nbsp;author:&nbsp;'John',
&nbsp;&nbsp;description:&nbsp;'A sample application',
&nbsp;&nbsp;license:&nbsp;'MIT'
}

5.3.10 else/catch放置

规则: 把else/catch放在if/try代码块关闭括号的同一行

编写条件语句时,建议将else放在if代码块关闭括号的同一行。同样,编写异常处理语句时,建议将catch放在try代码块关闭括号的同一行:

if&nbsp;(condition) {
&nbsp;&nbsp;doSomething()
}&nbsp;else&nbsp;{
&nbsp;&nbsp;doOther()
}

try&nbsp;{
&nbsp;&nbsp;riskyOperation()
}&nbsp;catch&nbsp;(e) {
&nbsp;&nbsp;handleError(e)
}

5.3.11 大括号风格

规则: 大括号 { 和语句在同一行

应保持一致的大括号风格。建议将大括号置于控制语句或声明语句的同一行:

if&nbsp;(condition) {
&nbsp;&nbsp;doSomething()
}

function&nbsp;greet():&nbsp;void&nbsp;{
&nbsp;&nbsp;console.log('Hello')
}

5.4 编程实践规范

5.4.1 添加类属性的可访问修饰符

规则: 建议添加类属性的可访问修饰符

ArkTS提供了private, protected和public可访问修饰符。默认情况下,属性的可访问修饰符为public。选取适当的可访问修饰符可以提升代码的安全性和可读性。

注意:如果类中包含private属性,无法通过对象字面量初始化该类。

class&nbsp;Person&nbsp;{
&nbsp;&nbsp;private&nbsp;name:&nbsp;string
&nbsp;&nbsp;protected&nbsp;age:&nbsp;number
&nbsp;&nbsp;public&nbsp;email:&nbsp;string

&nbsp;&nbsp;constructor(name:&nbsp;string,&nbsp;age:&nbsp;number,&nbsp;email:&nbsp;string) {
&nbsp; &nbsp;&nbsp;this.name&nbsp;= name
&nbsp; &nbsp;&nbsp;this.age&nbsp;= age
&nbsp; &nbsp;&nbsp;this.email&nbsp;= email
&nbsp; }
}

5.4.2 不省略浮点数小数点前后的0

规则: 不建议省略浮点数小数点前后的0

ArkTS中,浮点值包含一个小数点,不要求小数点之前或之后必须有一个数字。在小数点前面和后面都添加数字可以提高代码的可读性:

let&nbsp;price =&nbsp;0.5&nbsp; &nbsp;&nbsp;// 正确
let&nbsp;ratio =&nbsp;1.0&nbsp; &nbsp;&nbsp;// 正确

let&nbsp;bad =&nbsp;.5&nbsp; &nbsp; &nbsp; &nbsp;// 不推荐
let&nbsp;bad2 =&nbsp;1.&nbsp; &nbsp; &nbsp;&nbsp;// 不推荐

5.4.3 判断变量是否为Number.NaN

规则: 判断变量是否为Number.NaN时必须使用Number.isNaN()方法

在ArkTS中,Number.NaN是Number类型的一个特殊值。它被用来表示非数值。Number.NaN的独特之处在于它不等于任何值,包括其本身:

Number.NaN&nbsp;!==&nbsp;Number.NaN&nbsp;&nbsp;// true
Number.NaN&nbsp;!=&nbsp;Number.NaN&nbsp; &nbsp;// true

// 必须使用Number.isNaN()函数来测试
let&nbsp;value =&nbsp;Number.NaN
if&nbsp;(Number.isNaN(value)) {
&nbsp;&nbsp;console.log('值是NaN')
}

5.4.4 数组遍历优先使用Array对象方法

规则: 数组遍历优先使用Array对象方法

对于数组遍历,应该优先使用Array对象方法,如:forEach(), map(), every(), filter(), find(), findIndex(), reduce(), some():

let&nbsp;numbers = [1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5]

// 推荐
numbers.forEach(n&nbsp;=>&nbsp;console.log(n))
let&nbsp;doubled = numbers.map(n&nbsp;=>&nbsp;n *&nbsp;2)
let&nbsp;evens = numbers.filter(n&nbsp;=>&nbsp;n %&nbsp;2&nbsp;===&nbsp;0)
let&nbsp;sum = numbers.reduce((a, b) =>&nbsp;a + b,&nbsp;0)

5.4.5 不要在控制性条件表达式中执行赋值操作

规则: 不要在控制性条件表达式中执行赋值操作

控制性条件表达式用于 if、while、for 以及 ?: 等条件判断语句中。在控制性条件表达式中执行赋值容易导致意外行为,且降低代码的可读性:

// 不推荐
if&nbsp;(result =&nbsp;getData()) {
&nbsp;&nbsp;process(result)
}

// 推荐
let&nbsp;result =&nbsp;getData()
if&nbsp;(result) {
&nbsp;&nbsp;process(result)
}

5.4.6 finally代码块规范

规则: 在finally代码块中,不要使用return、break、continue或抛出异常,避免finally块非正常结束

在finally代码块中,直接使用return、break、continue、throw语句或调用方法时未处理异常,会导致finally代码块无法正常结束。finally代码块异常结束会影响try或catch代码块中异常的抛出,也可能影响方法的返回值。因此,必须确保finally代码块正常结束:

try&nbsp;{
&nbsp;&nbsp;riskyOperation()
}&nbsp;catch&nbsp;(e) {
&nbsp;&nbsp;handleError(e)
}&nbsp;finally&nbsp;{
&nbsp;&nbsp;cleanup() &nbsp;// 确保正常结束
}

5.4.7 避免使用ESObject

规则: 避免使用ESObject

ESObject主要用于ArkTS和TS/JS的跨语言调用场景中的类型标注。在非跨语言调用场景中使用ESObject标注类型,会引入不必要的跨语言调用,导致额外的性能开销。

5.4.8 使用T[]表示数组类型

规则: 使用T[]表示数组类型

ArkTS提供了两种数组类型的表示方式:T[]和Array。建议所有数组类型均使用T[]表示,以提高代码可读性:

let&nbsp;numbers:&nbsp;number[] = [1,&nbsp;2,&nbsp;3] &nbsp; &nbsp;// 推荐
let&nbsp;strings:&nbsp;string[] = ['a',&nbsp;'b'] &nbsp;&nbsp;// 推荐

let&nbsp;numbers2:&nbsp;Array<number> = [1,&nbsp;2,&nbsp;3] &nbsp;// 不推荐

第6章 ArkTS高性能编程实践

6.1 概述

本文提供应用性能敏感场景下的高性能编程建议,帮助开发者编写高性能应用。高性能编程实践是在开发过程中总结的一些高性能写法和建议。在实现业务功能时,应同步思考并理解高性能写法的原理,并将其应用于代码逻辑中。

6.2 声明与表达式优化

6.2.1 使用const声明不变的变量

不变的变量推荐使用const声明:

const&nbsp;APP_VERSION:&nbsp;string&nbsp;=&nbsp;'1.0.0'
const&nbsp;MAX_RETRY_COUNT:&nbsp;number&nbsp;=&nbsp;3
const&nbsp;API_BASE_URL:&nbsp;string&nbsp;=&nbsp;'https://api.example.com'

6.2.2 number类型变量避免整型和浮点型混用

针对number类型,运行时在优化时会区分整型和浮点型数据。建议避免在初始化后改变数据类型:

let&nbsp;count:&nbsp;number&nbsp;=&nbsp;0&nbsp; &nbsp; &nbsp;&nbsp;// 始终为整数
let&nbsp;price:&nbsp;number&nbsp;=&nbsp;0.0&nbsp; &nbsp;&nbsp;// 始终为浮点数

// 避免示例
let&nbsp;value:&nbsp;number&nbsp;=&nbsp;10&nbsp; &nbsp; &nbsp;// 整数
value =&nbsp;10.5&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 改变为浮点数,影响性能

6.2.3 数值计算避免溢出

常见的可能导致溢出的数值计算包括如下场景,溢出之后,会导致引擎走入慢速的溢出逻辑分支处理,影响后续的性能。

针对加法、减法、乘法、指数运算等运算操作: 应避免数值大于 INT32_MAX(2147483647)或小于 INT32_MIN(-2147483648)。

针对&(and)、>>>(无符号右移)等运算操作: 应避免数值大于 INT32_MAX

const&nbsp;INT32_MAX =&nbsp;2147483647
const&nbsp;INT32_MIN = -2147483648

function&nbsp;safeAdd(a:&nbsp;number,&nbsp;b:&nbsp;number):&nbsp;number&nbsp;{
&nbsp;&nbsp;if&nbsp;(a >&nbsp;0&nbsp;&& b >&nbsp;INT32_MAX - a) {
&nbsp; &nbsp;&nbsp;throw&nbsp;new&nbsp;Error('溢出风险')
&nbsp; }
&nbsp;&nbsp;return&nbsp;a + b
}

6.2.4 循环中常量提取

如果常量在循环中不会改变,可以将其提取到循环外部,减少访问次数:

// 优化前:每次循环都访问属性
for&nbsp;(let&nbsp;i =&nbsp;0; i < array.length; i++) {
&nbsp;&nbsp;let&nbsp;value = config.settings.defaultValue
&nbsp;&nbsp;process(array[i], value)
}

// 优化后:常量提取到循环外部
const&nbsp;defaultValue = config.settings.defaultValue
for&nbsp;(let&nbsp;i =&nbsp;0; i < array.length; i++) {
&nbsp;&nbsp;process(array[i], defaultValue)
}

6.3 函数优化

6.3.1 使用参数传递函数外的变量

使用闭包会造成额外的开销。在性能敏感场景中,建议使用参数传递函数外的变量替代:

// 不推荐:使用闭包(造成额外开销)
function&nbsp;createProcessor(config:&nbsp;Config) {
&nbsp;&nbsp;return&nbsp;function(data:&nbsp;Data) {
&nbsp; &nbsp;&nbsp;return&nbsp;processWithConfig(data, config)
&nbsp; }
}

// 推荐:使用参数传递
function&nbsp;processWithConfig(data:&nbsp;Data,&nbsp;config:&nbsp;Config):&nbsp;Result&nbsp;{
&nbsp;&nbsp;return&nbsp;process(data, config)
}

6.3.2 避免使用可选参数

函数的可选参数表示参数可能为undefined,在函数内部使用该参数时,需要进行非空值的判断,造成额外的开销。根据业务需求,将函数参数声明为必选参数。考虑使用默认参数:

// 不推荐:可选参数需要非空判断
function&nbsp;calculate(a:&nbsp;number,&nbsp;b?:&nbsp;number):&nbsp;number&nbsp;{
&nbsp;&nbsp;if&nbsp;(b !==&nbsp;undefined) {
&nbsp; &nbsp;&nbsp;return&nbsp;a + b
&nbsp; }
&nbsp;&nbsp;return&nbsp;a
}

// 推荐:使用默认参数
function&nbsp;calculate(a:&nbsp;number,&nbsp;b:&nbsp;number&nbsp;=&nbsp;0):&nbsp;number&nbsp;{
&nbsp;&nbsp;return&nbsp;a + b
}

6.4 数组优化

6.4.1 数值数组推荐使用TypedArray

涉及纯数值计算时,推荐使用TypedArray数据结构:

// 不推荐:普通数组
let&nbsp;numbers:&nbsp;number[] = []
for&nbsp;(let&nbsp;i =&nbsp;0; i <&nbsp;10000; i++) {
&nbsp; numbers.push(i)
}

// 推荐:TypedArray
let&nbsp;numbers:&nbsp;Int32Array&nbsp;=&nbsp;new&nbsp;Int32Array(10000)
for&nbsp;(let&nbsp;i =&nbsp;0; i <&nbsp;10000; i++) {
&nbsp; numbers[i] = i
}

TypedArray类型:

| 类型 | 说明 | 取值范围 | | — | — | — | | Int8Array | 8位有符号整数 | -128 ~ 127 | | Uint8Array | 8位无符号整数 | 0 ~ 255 | | Int16Array | 16位有符号整数 | -32768 ~ 32767 | | Uint16Array | 16位无符号整数 | 0 ~ 65535 | | Int32Array | 32位有符号整数 | -2147483648 ~ 2147483647 | | Uint32Array | 32位无符号整数 | 0 ~ 4294967295 | | Float32Array | 32位浮点数 | IEEE 754 | | Float64Array | 64位浮点数 | IEEE 754 |

6.4.2 避免使用稀疏数组

运行时在分配超过1024大小的数组或稀疏数组时,会采用hash表来存储元素。在该模式下,访问数组元素速度较慢。代码开发时应避免数组变成稀疏数组:

// 不推荐:稀疏数组(访问速度慢)
let&nbsp;sparse:&nbsp;number[] = []
sparse[10000] =&nbsp;1

// 推荐:预分配连续数组
let&nbsp;dense:&nbsp;number[] =&nbsp;new&nbsp;Array(10001).fill(0)
dense[10000] =&nbsp;1

6.4.3 避免使用联合类型数组

避免使用联合类型数组。避免在数值数组中混合使用整型数据和浮点型数据。根据业务需求,将相同类型的数据放在同一数组中:

// 不推荐
let&nbsp;mixed: (number&nbsp;|&nbsp;string)[] = [1,&nbsp;'two',&nbsp;3,&nbsp;'four']

// 推荐
let&nbsp;numbers:&nbsp;number[] = [1,&nbsp;2,&nbsp;3,&nbsp;4]
let&nbsp;strings:&nbsp;string[] = ['one',&nbsp;'two',&nbsp;'three',&nbsp;'four']

6.5 异常处理优化

6.5.1 避免频繁抛出异常

创建异常时会构造异常的栈帧,造成性能损耗。在性能敏感场景下,如for循环语句中,应避免频繁抛出异常:

// 不推荐:循环中频繁抛出异常
function&nbsp;processItems(items:&nbsp;Item[]):&nbsp;void&nbsp;{
&nbsp;&nbsp;for&nbsp;(let&nbsp;item&nbsp;of&nbsp;items) {
&nbsp; &nbsp;&nbsp;if&nbsp;(!isValid(item)) {
&nbsp; &nbsp; &nbsp;&nbsp;throw&nbsp;new&nbsp;Error(`Invalid item:&nbsp;${item.id}`)
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;process(item)
&nbsp; }
}

// 推荐:使用返回值处理错误
interface&nbsp;Result&nbsp;{
&nbsp;&nbsp;success:&nbsp;boolean
&nbsp;&nbsp;error?:&nbsp;string
}

function&nbsp;processItems(items:&nbsp;Item[]):&nbsp;Result&nbsp;{
&nbsp;&nbsp;for&nbsp;(let&nbsp;item&nbsp;of&nbsp;items) {
&nbsp; &nbsp;&nbsp;if&nbsp;(!isValid(item)) {
&nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp;success:&nbsp;false,&nbsp;error:&nbsp;`Invalid item:&nbsp;${item.id}`&nbsp;}
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;process(item)
&nbsp; }
&nbsp;&nbsp;return&nbsp;{&nbsp;success:&nbsp;true&nbsp;}
}

6.6 性能优化最佳实践总结

| 优化项 | 建议 | | — | — | | 变量声明 | 不变的变量使用 const | | 数值类型 | 避免整型和浮点型混用 | | 数值计算 | 避免溢出(注意 INT32 边界) | | 循环优化 | 提取循环内的常量 | | 函数设计 | 使用参数传递替代闭包 | | 函数参数 | 避免可选参数,使用默认参数 | | 数值数组 | 使用 TypedArray | | 数组设计 | 避免稀疏数组和联合类型数组 | | 异常处理 | 避免频繁抛出异常 |


第7章 HarmonyOS术语表

7.1 A

| 术语 | 全称 | 说明 | | — | — | — | | abc文件 | ArkCompiler Bytecode | 方舟字节码文件,是ArkCompiler的编译工具链以源代码作为输入编译生成的产物,文件后缀名为 .abc。在发布态,abc文件会被打包到HAP中 | | ANS | Advanced Notification Service | 通知增强服务,是HarmonyOS中负责处理通知的订阅、发布和更新等操作的系统服务 | | Atomic Service | 元服务 | 原名原子化服务,是HarmonyOS提供的一种面向未来的服务提供方式,是有独立入口的、免安装的用户应用程序形态 | | ArkUI | 方舟开发框架 | 为HarmonyOS平台开发极简、高性能、跨设备应用设计研发的UI开发框架,支撑开发者高效地构建跨设备应用UI界面 | | ArkCompiler | 方舟编译器 | 华为自研的统一编程平台,包含编译器、工具链、运行时等关键部件,支持高级语言在多种芯片平台的编译与运行 |

7.2 D

| 术语 | 全称 | 说明 | | — | — | — | | DFX | Design For X | 面向产品生命周期各环节的设计,其中X代表产品生命周期的某一个环节或特性。DFX设计涵盖了产品所有的非功能性设计 | | DV | Device Virtualization | 设备虚拟化,通过虚拟化技术可以实现不同设备的能力和资源融合 |

7.3 E

| 术语 | 说明 | | — | — | | ExtensionAbility | Stage模型中的组件类型名,即ExtensionAbility组件,提供特定场景(如卡片、输入法)的扩展能力,满足更多的使用场景 |

7.4 F

| 术语 | 说明 | | — | — | | FA模型 | HarmonyOS早期版本开始支持的应用模型,已经不再主推。建议使用新的Stage模型进行开发 |

7.5 H

| 术语 | 全称 | 说明 | | — | — | — | | HAP | Harmony Ability Package | 一个HAP文件包含应用的所有内容,由代码、资源、三方库及应用配置文件组成,其文件后缀名为 .hap | | HarmonyOS | – | 新一代智能终端操作系统,为不同设备的智能化、互联与协同提供了统一的语言。带来简洁、流畅、连续、安全可靠的全场景交互体验 | | HDF | Hardware Driver Foundation | 硬件驱动框架,用于提供统一外设访问能力和驱动开发、管理框架 | | HML | HarmonyOS Markup Language | 是一套类HTML的标记语言。通过组件、事件构建出页面的内容。页面具备数据绑定、事件绑定、列表渲染、条件渲染等高级能力 | | Hop | 流转 | 在HarmonyOS中泛指涉及多端的分布式操作。流转能力打破设备界限,多设备联动,使用户应用程序可分可合、可流转 |

7.6 I

| 术语 | 全称 | 说明 | | — | — | — | | IDN | Intelligent Distributed Networking | HarmonyOS特有的分布式组网能力单元。开发者可以通过IDN获取分布式网络内的设备列表和设备状态信息 |

7.7 K

| 术语 | 说明 | | — | — | | Kit | 是一个功能内聚的开放能力集合,可以支撑开发者完成一个特定场景的功能开发 |

7.8 M

| 术语 | 全称 | 说明 | | — | — | — | | Manual hop | 用户手动流转 | 是指开发者在用户应用程序中内嵌规范的流转图标,使用户可以手动选择合适的可选设备进行流转 | | MSDP | Mobile Sensing Development Platform | 移动感知平台。MSDP子系统提供分布式融合感知能力,借助HarmonyOS分布式能力,汇总融合来自多个设备的多种感知源 | | Multi-device collaboration | 多端协同 | 是一种实现用户应用程序流转的技术方案。指多端上的不同UIAbility协同运行或接力运行以实现完整业务 |

7.9 O

| 术语 | 说明 | | — | — | | OpenHarmony | 2020年,华为将HarmonyOS基础能力捐赠给开放原子开源基金会 |


附录

附录A 开发工具

DevEco Studio 是HarmonyOS应用开发的推荐IDE工具,提供以下功能:

  • • 工程创建与管理
  • • 代码编辑与智能提示
  • • 应用签名配置
  • • 应用调试与测试
  • • 应用安装与运行
  • • 预览器功能

附录B 学习路径

  1. 1. 入门阶段
  • • 了解HarmonyOS应用开发基本方法
  • • 构建首个HarmonyOS应用
  • • 掌握应用程序包结构
  • • 学习资源文件使用
  • • 掌握ArkTS核心功能和语法
  1. 2. 进阶阶段
  • • 深入学习各Kit开放能力
  • • 掌握UI组件和布局
  • • 学习应用架构设计
  • • 掌握多设备协同开发
  1. 3. 高级阶段
  • • 性能优化实践
  • • 安全开发规范
  • • 分布式能力开发
  • • 原生模块开发

附录C 参考资源

  • • HarmonyOS应用开发文档[1]
  • • ArkTS语言介绍[2]
  • • ArkTS编程规范[3]
  • • ArkTS高性能编程[4]
  • • HarmonyOS术语表[5]

引用链接

[1] HarmonyOS应用开发文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/application-dev-guide [2] ArkTS语言介绍: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/introduction-to-arkts [3] ArkTS编程规范: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-coding-style-guide [4] ArkTS高性能编程: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-high-performance-programming [5] HarmonyOS术语表: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/glossary


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:利刃信安 利刃信安 利刃信安《【应用开发】HarmonyOS 6 应用系统基于ArkTS编程语言的应用程序开发指南》

评论:0   参与:  0