ArkTS语言
ArkTS是HarmonyOS的默认开发言,基于TS做了扩展,相比较TS,ArkTS做了以下规则:
静态类型是ArkTS最重要的特性之一。如果使用静态类型,那么程序中变量的类型就是确定的。同时,由于所有类型在程序实际运行前都是已知的,编译器可以验证代码的正确性,从而减少运行时的类型检查,有助于性能提升。为实现最优性能,ArkTS禁止在程序执行期间更改对象布局。为获得更好的性能并鼓励编写清晰的代码,ArkTS限制了部分运算符的语义。对Structural typing的支持需要在语言、编译器和运行时进行大量的考虑和仔细的实现,当前ArkTS不支持该特性。ArkTS兼容TS和JS,未来可能持续演进,逐步增强并行和并发能力、扩展系统类型,以及引入分布式开发范式等更多特性。
声明
类型
类型名 | 类型 | 支持样式 | 案例 |
number | 数字 | 十进制 | let i = 10; |
十六进制 | let i = 0xAD; |
八进制 | let i = 0O51; |
二进制 | let i = 0b1110; |
浮点数 | let f = 3.14123; |
e指数 | let f =3e1; |
boolean | 布尔值 | | let result: boolean = false; |
string | 字符串 | 双引号 | let s = "Hello World"; |
单引号 | let s ='Hello World'; |
模板文字 | let format = `Result: ${s}`; |
void | | | |
Object | 对象 | | |
array | 数组 | | let names: string[] = ['Alice', 'Bob', 'Carol']; |
enum | 枚举 | | enum ColorSet { Red, Green, Blue } |
Union | 联合体 | | |
Aliases | 匿名 | | |
运算符
运算符 | 说明 |
= | 赋值运算符 |
+= | 符合运算符 |
-= | |
*= | |
/= | |
%= | |
<<= | |
>>= | |
>>>= | |
&= | |
|= | |
^= | |
=== | 全等 |
!== | 全不相等 |
== | 相等 |
!= | 不等 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 余数 |
& | 与 |
| | 或 |
^ | 异或 |
~ | 非 |
<< | 左移 |
>> | 右移 |
>>> | 右移补零 |
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
其他运算符
instanceof:用于在运行时检查一个对象是否是指定类或其子类的实例。
语句
if语句
if(条件1){执行1}else if(条件2){执行2}else{执行3}
switch语句
switch(表达式) { case 条件1: 执行1 break; case 条件2: 执行2 break; case 条件3: 执行3 break; default: 执行4 break;}
for语句
for of语句
while语句
do while语句
break语句
中止循环
contine语句
跳过当前
try catch语句
try{ 执行 }catch(报错){ 执行报错处理 }
try catch finally语句
try{ 执行 }catch(报错){ 执行报错处理 }finally{ 执行必须处理 }
函数
声明
函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体。
function 函数名(参数名:参数类型): 返回值类型{ 函数体 }
可选参数:参数名?:参数类型
函数的作用域
函数调用
调用函数以执行其函数体,实参值会赋值给函数的形参。
函数类型
type 名称 = (参数名:参数类型) { 函数体}
匿名函数
let 名称 = (参数名:参数类型) => 函数体;
闭包函数
闭包是由函数及声明该函数的环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。
特点:
- 会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
function 函数名():() => 返回值{ 函数体 let 内部函数名 = ():返回值 => 函数体 return 内部函数;}
函数重载
function 函数名(参数:参数类型1) { 函数体}function 函数名(参数:参数类型2) { 函数体}function 函数名(参数:参数类型3) { 函数体}
类
字段
字段是直接在类中声明的某种类型的变量。
类可以具有实例字段或者静态字段。
实例字段
实例字段存在于类的每个实例上。每个实例都有自己的实例字段集合。
静态字段
使用关键字static将字段声明为静态。静态字段属于类本身,类的所有实例共享一个静态字段。
字段初始化
为了减少运行时错误并提升执行性能,ArkTS要求所有字段在声明时或构造函数中显式初始化,与标准TS的strictPropertyInitialization模式相同。
getter和setter
setter和getter可用于提供对类属性的受控访问。
在类中可以定义getter或者setter。
方法
方法属于类。类可以定义实例方法或者静态方法。静态方法属于类本身,只能访问静态字段。而实例方法既可以访问静态字段,也可以访问实例字段,包括类的私有字段。
实例方法
必须通过类的实例调用实例方法。
静态方法
使用关键字 static 声明静态方法。静态方法属于类,只能访问静态字段。静态方法定义了类作为一个整体的公共行为。必须通过类名调用静态方法。
继承
一个类可以继承另一个类(称为基类),并实现多个接口。继承类继承基类的字段和方法,但不继承构造函数。继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。
基类也称为“父类”或“超类”。继承类也称为“派生类”或“子类”。
class [extendsBaseClassName] [implementslistOfInterfaces] { // ...}
父类访问
关键字super可用于访问父类的方法和构造函数。
方法重写
子类可以重写其父类中定义的方法的实现。重写的方法必须具有与原始方法相同的参数类型和相同或派生的返回类型。
方法重载签名
通过重载签名,指定方法的不同调用。具体方法为,为同一个方法写入多个同名但签名不同的方法头,方法实现紧随其后。
如果两个重载签名的名称和参数列表均相同,则为错误。
class 类型 { 方法名(参数名: 类型1): 返回值类型; 方法名(参数名: 类型2): 返回值类型; 方法名(参数名: 类型1 | 类型2): 返回值类型 { 签名实现 }}
构造函数
类声明可以包含用于初始化对象状态的构造函数。如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数。
派生类的构造函数
构造函数函数体的第一条语句可以使用关键字super来显式调用直接父类的构造函数。
构造函数重载签名
可以通过编写重载签名,指定构造函数的不同调用方式。
可见性修饰符
类的方法和属性都可以使用可见性修饰符。
可见性修饰符包括:private、protected和public。默认可见性为public。
类型 | 说明 |
Public | 成员在程序的任何可访问该类的地方都是可见的。 |
Private | 成员不能在声明该成员的类之外访问。 |
Protected | 成员允许在派生类中访问,但不能在声明该成员的类之外访问。 |
对象字面量
对象字面量是一个表达式,可用于创建类实例并提供一些初始值。它在某些情况下更方便,可以用来代替new表达式。
对象字面量的表示方式是:封闭在花括号对({})中的'属性名:值'的列表。
class C { public n: number = 0; public s: string = '';}let c: C = {n: 42, s: 'foo'};
Record类型的对象字面量
泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。
let map: Record<string, number> = { 'John': 25, 'Mary': 21};
抽象类
带有abstract修饰符的类称为抽象类。抽象类可用于表示一组更具体的概念所共有的概念。抽象类的子类可以是抽象类也可以是非抽象类。抽象父类的非抽象子类可以实例化。
抽象方法
带有abstract修饰符的方法称为抽象方法,抽象方法可以被声明但不能被实现。
接口
接口声明引入新类型。接口是定义代码协定的常见方式。
任何类的实例,只要实现了特定接口,即可通过该接口实现多态。
接口通常包含属性和方法的声明。
接口属性
接口属性可以是字段、getter、setter或getter和setter组合的形式。
属性字段只是getter/setter对的便捷写法。
接口继承
接口可以继承其他接口。
抽象类和接口
抽象类与接口都无法实例化。抽象类是类的抽象,抽象类用来捕捉子类的通用特性,接口是行为的抽象。
区别
- 一个类只能继承一个抽象类,而一个类可以实现一个或多个接口
- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法
- 抽象类里面可以有方法的实现,但是接口没有方法的实现,是完全抽象的
泛型类型和函数
泛型类型和函数使代码能够以类型安全的方式操作多种数据类型,而无需为每种类型编写重复的逻辑。
泛型类和接口
类和接口可以定义为泛型,将参数添加到类型定义中。
泛型约束
泛型类型的类型参数可以被限制只能取某些特定的值。
泛型函数
使用泛型函数可编写更通用的代码。
泛型默认值
泛型类型的类型参数可以设置默认值,这样无需指定实际类型实参,直接使用泛型类型名称即可。
空安全
默认情况下,ArkTS中的所有类型都不允许为空,这类似于TypeScript的(strictNullChecks)模式,但规则更严格。
可以为空值的变量定义为联合类型T | null。
非空断言运算符
后缀运算符!可用于断言其操作数为非空。
当应用于可空类型的值时,编译时类型会变为非空类型。例如,类型从T | null变为T:
空值合并运算符
空值合并二元运算符??用于检查左侧表达式的求值是否等于null或者undefined。如果是,则表达式的结果为右侧表达式;否则,结果为左侧表达式。
可选链
访问对象属性时,如果属性是undefined或null,可选链运算符返回undefined。
模块
程序可划分为多组编译单元或模块。
每个模块都有其自己的作用域,即在模块中创建的任何声明在该模块之外都不可见,除非它们被显式导出。
与此相对,必须首先将另一个模块导出的变量、函数、类、接口等导入到当前模块中。
导出
可以使用关键字export导出顶层的声明。
未导出的声明名称被视为私有名称,只能在声明该名称的模块中使用。
导入
静态导入
导入声明用于导入从其他模块导出的实体,并在当前模块中提供其绑定。导入声明由两部分组成:
导入路径,用于指定导入的模块;
导入绑定,用于定义导入的模块中的可用实体集和使用形式。
动态导入
在应用开发的有些场景中,如果希望根据条件导入模块或者按需导入模块,可以使用动态导入代替静态导入。
import()语法被称为动态导入(dynamic import),是一种类似函数的表达式,用于动态导入模块。调用这种方式,会返回一个promise。
导入HarmonyOS SDK
HarmonyOS SDK提供的开放能力也需要在导入声明后使用。可直接导入接口模块来使用该模块内的所有接口能力。
SDK对同一个Kit下的接口模块进行了封装,开发者在示例代码中可通过导入Kit的方式来使用Kit所包含的接口能力。其中,Kit封装的接口模块可查看SDK目录下Kit子目录中各Kit的定义。在代码开发中,推荐通过导入Kit方式使用开放能力。
通过导入Kit方式使用开放能力有三种方式:
导入Kit下单个模块的接口能力。
import { UIAbility } from '@kit.AbilityKit';
导入Kit下多个模块的接口能力。
import { UIAbility, Ability, Context } from '@kit.AbilityKit';
导入Kit包含的所有模块的接口能力。
import * as module from '@kit.AbilityKit';
this
关键字this只能在类的实例方法中使用。
使用限制:
关键字this的指向:
注解
注解是一种语言特性,它通过添加元数据来改变应用声明的语义。
- 注解ClassAuthor需要将元信息添加到类声明中。
对于要使用的注解,其名称必须以符号@,如果在使用位置无法访问注解名称,则会发生编译错误。注解声明可以导出并在其他文件中使用。多个注解可以应用于同一个声明。
用户自定义注解
用户自定义注解的定义与interface的定义类似,其中的interface关键字以符号@为前缀。
注解字段仅限于下面列举的类型:
注解字段的默认值必须使用常量表达式来指定。
常量表达式的场景如下所示:
注意:
- 注解必须定义在顶层作用域(top-level),否则会出现编译报错。
- 注解的名称不能与注解定义所在作用域内可见的其他实体名称相同,否则会出现编译报错。
- 注解不支持类型Typescript中的合并,否则会出现编译报错。
- 注解不支持在类的getter和setter方法中添加,若添加注解会编译报错。
导入和导出注解
注解也可以被导入导出。针对导出,当前仅支持在定义时的导出,即export @interface的形式。
针对导入,当前仅支持import {}和import * as两种方式。
注意:
- 由于注解不是类型,因此禁止使用type符号进行导入和导出。
.d.ets文件中的注解
注解可以出现在.d.ets文件中。可以在.d.ets文件中用环境声明(ambient declaration)来声明注解。
编译器自动生成的.d.ets文件
当编译器根据ets代码自动生成.d.ets文件时,存在以下2种情况。
- 当注解定义被导出时,源代码中的注解定义会在.d.ets文件中保留。
- 当下面所有条件成立时,源代码中实体的注解实例会在.d.ets文件中保留。
注解的定义被导出(import的注解也算作被导出)。
如果实体是类,则类被导出。如果实体是方法,则类被导出,并且方法不是私有方法。
开发者生成的.d.ets文件
开发者生成的.d.ets文件中的注解信息不会自动应用到实现的源代码中。
重复注解和继承
同一个实体不能重复使用同一注解,否则会导致编译错误。
子类不会继承基类的注解,也不会继承基类方法的注解。
注解和抽象类、抽象方法
不支持对抽象类或抽象方法使用注解,否则将导致编译错误。
源码态注解
源码态注解为一类特殊形式的注解。源码态注解的生命周期只在编译期,不会影响编译产物。
开发者可以通过使用ArkTS提供的Retention接口来构造自定义源码态注解。源码态注解有更广的使用范围,支持在以下声明上使用: