购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第2章
ArkTS基本知识

本章将深入探讨ArkTS语言,这是一种在开发和测试领域具有广泛应用的编程语言。笔者将以通俗易懂的语言,引导读者逐步进入ArkTS的世界,详细讲解ArkTS的基本语法规则,以及如何在实际开发和测试工作中运用这些规则。这些内容是本章的重点。

对于任何编程语言来说,掌握其基本规则至关重要。这不仅是为了熟悉语言本身,更是为了在未来深入学习更高级的开发技术时能够游刃有余。正如建造高楼大厦,基础打得越深越牢,大厦才能更高更稳固。

通过本章的学习,读者不仅能全面了解ArkTS,还能熟练运用它进行单元测试——这是确保代码质量的重要手段。同时,读者将深入理解并掌握ArkTS的语法,为未来的编程学习和实践打下坚实基础。

2.1 初识ArkTS

ArkTS是HarmonyOS NEXT的主力应用开发语言。它基于TypeScript(简称TS)生态进行扩展,在保持TypeScript的基本风格的同时,通过规范定义强化了开发期的静态检查和分析,从而显著提升程序执行的稳定性和性能。

1.ArkTS与标准TypeScript的差异

从API 10开始,ArkTS通过规范进一步强化了静态检查和分析。ArkTS与标准TypeScript存在以下主要差异:

1)强制使用静态类型

静态类型是ArkTS的核心特性之一。在静态类型的约束下,程序中变量的类型在编译时是确定的。由于所有类型在程序实际运行前即可确定,因此编译器可以验证代码的正确性,从而减少运行时的类型检查,有助于提升性能。

2)禁止在运行时改变对象布局

为实现最佳性能,ArkTS要求在程序执行期间不能更改对象的布局结构。

3)限制运算符语义

为了获得性能并鼓励开发者编写更清晰的代码,ArkTS对部分运算符的语义进行了限制。例如,一元加法运算符仅适用于数值类型,不能用于其他类型的变量。

4)不支持Structural Typing

ArkTS当前不支持Structural Typing(结构化类型)。这一特性需要在语言设计、编译器实现和运行时考虑周全。目前ArkTS的开发策略是优先满足其他需求,但根据实际场景和反馈,未来可能会重新评估这一特性。

2.ArkTS扩展的功能

在当前的在UI开发框架中,ArkTS主要扩展了以下功能:

1)基本语法

ArkTS支持声明式UI描述、自定义组件以及动态扩展UI元素。结合ArkUI开发框架的系统组件、事件方法和属性方法,构成了UI开发的核心能力。

2)状态管理

ArkTS提供多维度的状态管理机制。与UI关联的数据既可以在组件内使用,也可以在不同组件层级间(如父子组件、爷孙组件之间)传递,甚至支持在全局范围或跨设备传递。数据传递形式包括只读的单向传递和可变更的双向传递,开发者可灵活利用这些功能实现数据和UI的联动。

3)渲染控制

ArkTS提供了多样化的渲染控制能力。除了通过自定义组件的build()函数和@Builder装饰器中的声明式UI描述语句外,还可以使用渲染控制语句来辅助UI的构建,这些渲染控制语句包括:

● 条件渲染:控制组件是否显示。

● 循环渲染:基于数组快速生成组件。

● 数据懒加载:适用于特定大数据量场景。

● 混合模式渲染:针对混合模式开发的组件渲染。

ArkTS兼容TypeScript和JavaScript生态,开发者可以使用TypeScript和JavaScript进行开发或复用已有代码。未来,ArkTS将结合应用开发和运行的实际需求,持续演进,逐步增加并行和并发能力、系统类型支持,并引入分布式开发范式等更多特性。

2.2 DevEco Studio的使用

本书中的所有代码均可在DevEco Studio中编写单元测试用例进行验证。本节将详细介绍如何使用DevEco Studio编写单元测试用例进行测试。

2.2.1 新建工程

在测试前,需要创建一个工程,具体步骤如下:

步骤01 在新建工程界面,选择EmptyAbility模板,然后单击Next按钮进行下一步设置,如图2-1所示。

图2-1 DevEco Studio新建工程界面

步骤02 填写工程名称后,单击Finish按钮完成工程的创建,如图2-2所示。

图2-2 设置工程名称

2.2.2 自动化测试框架

1.概述

自动化测试框架arkxtest是工具集的重要组成部分,支持TypeScript和JavaScript语言的单元测试框架(JsUnit)及UI测试框架(UiTest)。

● JsUnit提供单元测试用例的执行能力,包括提供编写单元测试用例的基础接口以及用于测试系统或应用的接口,支持开发者编写和执行单元测试用例,同时生成对应的测试报告。

● UiTest提供简捷易用的API,支持查找和操作界面控件的能力,方便开发者编写基于界面操作的自动化测试脚本。

2.实现原理

测试框架由单元测试框架和UI测试框架组成。

● 单元测试框架是整个测试框架的基础,提供了用例识别、调度、执行及结果汇总等核心能力。

● UI测试框架对外提供UiTest API,供开发者在相关测试场景中调用,其脚本运行仍依赖单元测试框架的基础功能。

3.单元测试框架

单元测试框架由核心测试管理(CORE)与扩展测试管理(EXT)组成,它的主要功能结构如图2-3所示。

图2-3 单元测试框架的主要功能

测试可通过aa命令行进行,使用命令行脚本测试的流程如图2-4所示。

图2-4 脚本基础流程运行图

4.UI测试框架

UI测试框架的主要功能如图2-5所示。

图2-5 UI测试框架主要功能

5.约束与限制

UI测试框架的功能在HarmonyOS 3.1 release版本之后方可使用,而历史版本不支持这些功能。

2.2.3 环境准备

自动化脚本的编写主要基于DevEco Studio,建议使用DevEco Studio 3.0或更高的版本进行脚本的编写。脚本的执行需要计算机连接硬件设备,例如开发板等。

2.2.4 新建和编写测试脚本

1.新建测试脚本

(1)在DevEco Studio中新建应用开发工程之后,ohos目录即为测试脚本所在的目录。

(2)在工程目录下打开待测试模块的ets文件,将光标置于代码中的任意位置,右击代码,在弹出的快捷菜单中选择依次选择Show Context Actions→Create Ohos Test选项,或者按快捷键Alt+Enter,并选择Create Ohos Test,创建测试类。

2.编写单元测试脚本

在单元测试框架中,测试脚本需要包含以下基本元素:

(1)依赖包:用于调用测试框架的相关接口。

(2)测试代码:编写测试逻辑,例如接口调用和功能验证。

(3)断言接口:设置测试代码中的检查点。若脚本中没有检查点,则不是一个完整的测试脚本。

以下是一个测试脚本示例(见文件2-1)。

文件2-1 测试脚本代码

这段代码是使用OHOS(开放鸿蒙操作系统)测试框架Hypium编写的一个自动化测试脚本,用于测试OHOS应用的Ability(即能力,是HarmonyOS应用程序提供的抽象功能)的UI功能。代码的具体解释如下:

● import { describe, it, expect } from '@ohos/hypium';:导入Hypium测试框架中的describe、it和expect函数,这些函数用于组织测试用例和断言操作。

● import { abilityDelegatorRegistry } from '@kit.TestKit';:导入测试工具包中的abilityDelegatorRegistry,该模块提供了注册和获取能力代理(AbilityDelegator)的方法。

● import { UIAbility, Want } from '@kit.AbilityKit';:导入UIAbility和Want类型,分别代表用户界面能力和启动能力所需的信息结构。

● const delegator = abilityDelegatorRegistry.getAbilityDelegator();:获取能力代理实例,用于启动和管理测试中的能力。

● const bundleName = abilityDelegatorRegistry.getArguments().bundle Name;:获取当前测试用例对应的bundleName,通常用于指定应用的包名。

● function sleep(time: number) { ... }:定义一个sleep函数,该函数返回一个在指定时间后解决的Promise,用于在测试中添加延迟。

● export default function abilityTest() { ... }:定义一个默认导出的测试函数,供Hypium测试框架执行。

● describe('ActsAbilityTest', () => { ... }):定义一个测试套件,describe用于组织多个相关的测试用例。

● it('testUiExample', 0, async (done: Function) => { ... }):定义一个测试用例,it的第一个参数为测试用例的名称,第二个参数是超时时间(0表示无超时限制),第三个参数为异步测试函数。

● console.info("uitest: TestUiExample begin");:向控制台输出测试开始的信息。

● const want: Want = { ... }:创建一个Want对象,指定要启动能力的bundleName和abilityName。

● await delegator.startAbility(want);:使用能力代理启动指定的能力。

● await sleep(1000);:等待1000毫秒,确保能力有足够的时间启动并显示。

● await delegator.getCurrentTopAbility().then((Ability: UIAbility) =>{ ... }):获取当前最顶层的能力,并在回调函数中处理结果。

● expect(Ability.context.abilityInfo.name).assertEqual('EntryAbili ty');:使用expect函数断言,检查最顶层能力的名称是否为'EntryAbility'。

● done();:通知测试框架测试用例已完成。

这个测试脚本的目的是验证应用是否能够正确启动名为“EntryAbility”的能力,并确保该能力成为最顶层的能力。测试用例结合了异步操作和断言,以确保测试结果的准确性。

2.2.5 DevEco Studio执行测试脚本

在DevEco Studio中,执行测试脚本只需单击按钮即可。当前支持以下3种执行方式:

(1)测试包级别执行:执行测试包内的全部用例。

(2)测试套级别执行:执行describe方法中定义的全部测试用例。

(3)测试方法级别执行:执行指定it方法,即单个测试用例。

在DevEco Studio中创建测试用例的步骤如下:

步骤01 在需要测试的ets文件中右击,在弹出的快捷菜单中选择Show Context Actions选项,如图2-6所示。

图2-6 DevEco Studio创建测试用例步骤1

步骤02 在弹出的菜单中选择Create Local Text选项,如图2-7所示。

图2-7 DevEco Studio中创建测试用例步骤2

步骤03 在弹出的窗口中填写测试案例的名称,如图2-8所示。注意,ArkTS name的值需要以“.test”结尾。

图2-8 DevEco Studio中创建测试用例步骤3

步骤04 在创建成功后,测试用例代码中包含了测试套级别和测试方法级别的示例代码。这些代码前的绿色小箭头,表示是可以直接执行的代码,如图2-9所示。

图2-9 DevEco Studio中创建测试用例步骤4

步骤05 根据开发需求修改测试用例中的代码。如图2-10所示,可以在当前测试文件中修改代码,并直接在文件顶级区域编写代码进行测试。

图2-10 DevEco Studio中运行测试用例

在图2-10中,可以通过以下两种方式执行测试:

● 单击代码前面的绿色箭头,执行测试套级别或测试方法级别测试。

● 在空白处右击,在弹出的快捷菜单中选择直接执行测试。

2.2.6 查看测试结果

测试执行完毕后,可直接在DevEco Studio中查看测试结果,如图2-11所示。

图2-11 DevEco Studio中运行测试用例的结果

2.3 ArkTS的基本语法规则

本节将介绍ArkTS的基本语法规则,包括变量和常量的声明(declaration)、自动类型推断、类型定义、运算符和语句。

2.3.1 声明

在编程语言中,声明是一种特殊的语句,用于向程序引入或定义元素,如变量、常量、类型、函数或类等。声明提供了这些元素的名称和一些基本信息,但不会立即分配存储空间或执行任何操作。

1.变量声明

声明的变量以关键字let开头,表示该变量在程序执行期间可以拥有不同的值。例如:

let hi: string = 'hello';
hi = 'hello, world';

代码解释如下:

● 第1行代码使用let关键字声明了一个变量hi,并指定其类型为string(字符串),同时将'hello'这个字符串赋值给了hi。

● 第2行代码将hi变量的值更新为'hello, world'。这行代码没有重新指定类型,因为在TypeScript中,如果变量的类型已经声明了,那么后续对该变量的赋值可以是隐式类型(即省略声明),只要新值与之前声明的类型兼容即可。

2.常量声明

常量的值在程序运行期间不可变更,因为它的值在编译期已经确定。常量的声明以关键字const开头,并且只能被赋值一次。例如:

const hello: string = 'hello';

上述代码声明了一个名为hello的常量,它的类型被明确指定为string,并初始化为字符串'hello'。

注意

如果尝试对常量重新赋值,会导致编译错误。编译器会抛出异常,因为这违反了常量的只读原则。

2.3.2 自动类型推断

由于ArkTS是一种静态类型语言,因此所有数据的类型都必须在编译时确定。然而,如果一个变量或常量的声明包含初始值,那么开发者可以省略显式的类型声明。

例如,下面两种声明方式均有效,两个变量的类型都被推断为string类型:

let hi1: string = 'hello';
let hi2 = 'hello, world';

代码解释如下:

● 第1行代码声明了一个名为hi1的变量,显式指定了它的类型为string,并将它初始化为字符串'hello'。

● 第2行代码声明了一个名为hi2的变量,未显式指定它的类型。在ArkTS中,如果变量的类型可以通过赋值表达式推断,那么可以省略类型声明。这里,hi2被推断为string类型,并被初始化为字符串'hello, world'。

2.3.3 类型

类型是一个基本概念,用于定义数据的分类和操作规则。类型系统是编程语言的重要组成部分之一,它与数据的存储、操作以及程序的安全性相关联。以下是ArkTS中常见的类型。

1.number类型

在ArkTS中,number类型用于表示数值,包括整数和浮点数。它与JavaScript和TypeScript中的number类型类似,可用于各种数值计算和操作。

整数变量包括以下类别:

(1)由数字序列组成的十进制整数,例如0、117、-345。

(2)以0x(或0X)开头的十六进制整数,可包含数字0~9和字母~f或A~F,例如0x1123、0x00111、-0xF1A7。

(3)以0o(或0O)开头的八进制整数,只能包含数字0~7,例如0o777。

(4)以0b(或0B)开头的二进制整数,只能包含数字0和1,例如0b11、0b0011、-0b11。

浮点数变量包括以下3个部分:

(1)十进制整数,可以是有符号数(即前缀为“+”或“-”)。

(2)小数点(.)。

(3)小数部分(由十进制数字字符串表示)。

浮点数示例:3.14、-0.15。

浮点数还可包含以e或E开头的指数部分,后跟有符号(即前缀为“+”或“-”)或无符号整数,用于表示数值的数量级。例如1.5e10、-2.5E-3、3.0e+7。

number类型用法的示例代码如文件2-2所示。

文件2-2 number类型用法的示例代码

//声明一个名为 n1 的变量,并将其初始化为浮点数 3.14
let n1 = 3.14;
//声明一个名为 n2 的变量,并将其初始化为浮点数 3.141592
let n2 = 3.141592;
//声明一个名为 n3 的变量,并将其初始化为浮点数 0.5
//注意,这个数值前的点表示它是一个十进制数
let n3 = .5;
//声明了一个名为 n4 的变量,并使用科学记数法将其初始化为 10 的 10 次方,即 10000000000
let n4 = 1e10;
2.boolean类型

boolean(布尔)类型由true(真)和false(假)两个逻辑值组成。boolean类型的变量通常在条件语句中使用,如文件2-3所示。

文件2-3 boolean类型用法的示例代码

let isDone: boolean = false;
// ...
console.log('Done!');

代码解释如下:

● let isDone: boolean = false;:这行代码声明了一个名为isDone的变量,显式指定其类型为boolean(布尔)。boolean类型型变量只能有两个值:true或false。这里,isDone被初始化为false。

● console.log('Done!');:如果isDone为true,这行代码将被执行,在控制台输出字符串'Done!'。

3.string类型

string代表字符串,由一系列字符组成,这些字符可以是数字、字母和下画线。字符串可以组合成完整的信息表达,在数据处理、用户输入、数据输出和功能描述等场景中广泛应用。

在字符串中,可以使用转义字符表示具有特殊含义的字符,例如换行符、制表符和引号等。这使得在字符串中能够安全地包含这些字符。常见的转义字符包括\'(单引号)、\"(双引号)、\\(反斜杠)、\n(换行符)和\t(制表符)等。

字符串变量由单引号(')或双引号(")包围的零个或多个字符组成。此外,还有一种特殊形式的字符串,使用反向单引号(`)包围,即模板字符串。

string类型用法的示例代码如文件2-4所示。

文件2-4 string类型用法的示例代码

let s1 = 'Hello, world!\n';
let s2 = 'this is a string';
let a = 'Success';
let s3 = `The result is ${a}`;

以上代码演示了不同字符串字面量和模板字符串的使用,具体解析如下:

● let s1 = 'Hello, world!\n';:声明了一个名为s1的变量,它是一个由单引号包围的字符串。该字符串中包含了文本“Hello, world!”和一个换行符\n,这意味着在输出“Hello, world!”时后会换行。

● let s2 = 'this is a string';:声明了一个名为s2的变量,其值是由单引号包围的字符串,包含了文本“this is a string”。

● let a = 'Success';:声明了一个名为a的变量,它是一个字符串,其值包含了文本“Success”。

● let s3 = The result is ${a};:声明了一个名为s3的变量,它的值是模板字符串,由反引号(``)包围。模板字符串允许在字符串中嵌入变量或表达式,其中${a}表示将变量a的值嵌入字符串中。因此,如果变量a的值是“Success”,那么s3的值将是'The result is Success'。

模板字符串是ES6(ECMAScript 2015)新增的特性,为含有变量的字符串提供了更便捷的定义方式。在模板字符串中,可使用${}来插入变量或者表达式的值。

4.void类型

void类型用于指定函数没有返回值。此类型的唯一可能值为void。由于void是引用类型,因此它也可以用于泛型类型参数。void类型用法的示例代码如文件2-5所示。

文件2-5 void类型用法的示例代码

class Class<T> {
  //...
}

let instance: Class<void>

这段代码定义了一个泛型类Class,该类可以接收任何类型作为参数。变量instance是该类的一个实例,类型参数被指定为void类型,表明该实例不需要处理任何具体的类型值。

5.Object类型

Object类型是所有引用类型的基类型。它提供了一种通用方式来处理不同类型的对象,使各种数据类型可以以统一方式进行操作。

Object类型具有以下特性:

(1)基类型:Object是所有引用类型的基类,所有自定义对象、类实例和数组等都隐式继承自Object。

(2)自动装箱(autoboxing):基本数据类型(如整数、浮点数、布尔值等)可以被自动装箱,即转换为对应的对象类型,从而赋值给Object类型的变量。例如,整数5被视为Integer对象。

(3)通用性:由于Object是所有对象的基类,因此可以使用Object类型的变量来存储任何引用类型的对象。这种通用性使得数据结构(如集合和容器)能够存储多种不同类型的对象。

Object类型用法的示例代码如文件2-6所示。

文件2-6 Object类型用法的示例代码

6.array类型

Array表示数组,是由符合数组声明中指定的元素类型的数据组成。数组可通过数组字面量(即用方括号括起来的零个或多个表达式组成的列表,其中每个表达式表示数组中的一个元素)进行赋值。数组的长度由数组中元素的个数决定。数组中第一个元素的索引值为0。

以下语句将创建包含3个元素的数组:

let names: string[] = ['Alice', 'Bob', 'Carol'];
7.enum类型

enum类型又称枚举类型,是由一组预先定义的命名值组成的值类型。这些命名值称为枚举常量。

使用枚举常量时,必须以枚举类型名称为前缀,例如:

enum ColorSet { Red, Green, Blue };

let c: ColorSet = ColorSet.Red;

常量表达式可用于显式设置枚举常量的值,例如:

enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 };

let c: ColorSet = ColorSet.Black;
8.union类型

union类型(联合类型)是由多个类型组合而成的引用类型。它表示变量可以是多个类型之一。声明union类型通常使用管道符(|)来组合不同的类型。union类型用法的示例代码如文件2-7所示。

文件2-7 union类型用法的示例代码

可以使用特定机制来获取union类型中特定类型的值,如文件2-8的示例代码所示。

文件2-8 获取union类型中特定类型的值的示例代码

9.aliases类型

aliases类型为匿名类型(如数组、函数、对象变量或联合类型)提供名称,或为已有类型提供替代名称,即取别名。aliases类型使用关键字type来声明,其示例代码如文件2-9所示。

文件2-9 aliases类型用法的示例代码

关键代码解释如下:

● type Matrix = number[][];:定义了Matrix类型别名。Matrix被定义为一个二维数组,其中数组的元素是数字(number)。这意味着Matrix类型可以用来表示任何形式的数字矩阵。

● type Handler = (s: string, no: number) => string;:定义了Handler类型别名。Handler是一个函数类型,接收两个参数:一个字符串类型的参数s和一个数字类型的参数no,并返回一个字符串类型的结果。

● type Predicate<T> = (x: T) => Boolean;:定义了Predicate<T>类型别名。Predicate<T>是一个泛型函数类型,接收一个类型为T的参数x,并返回一个布尔值。

● type NullableObject = Object | null;:定义了NullableObject类型别名。NullableObject被定义为可以是Object类型或null。这意味着任何NullableObject类型的值要么是一个对象,要么是null,对于表示可能不存在的对象非常有用。

2.3.4 运算符

运算符是编程语言中的一个符号,用于指示编译器或解释器对操作数执行特定的数学或逻辑运算。操作数可以是变量、常量或表达式。以下是一些常见的运算符类型。

1.赋值运算符

赋值运算符为“=”,用于将一个值赋给一个变量。使用方式如x=y。

复合赋值运算符将赋值操作与运算组合在一起,例如x op = y等于x = x op y。

常用的复合赋值运算符有:+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=。

2.比较运算符

比较运算符用于比较两个值之间的关系,其运算结果为布尔值(true或false)。常见比较运算符及其说明如表2-1所示。

表2-1 比较运算符

3.算术运算符

算术运算符是用于执行基的本数学运算。根据操作数的个数,常见的算术运算符可分为一元运算符和二元运算符(或者成为单目运算符或者双目运算符)。其中,一元运算符操作一个操作数,二元运算符操作两个操作数。

● 一元运算符:一个操作数参与运算,包括-(负号)、+(正号)、--(自减)、++(自加)。

● 二元运算符:两个操作数参与运算,常见的二元运算符及其说明如表2-2所示。

表2-2 二元运算符

4.位运算符

位运算符是一组用于对整数的二进制位进行操作的运算符。这些运算符通常用于底层系统编程和性能优化,因为它们可以直接操作内存中的位模式。位运算符及其说明如表2-3所示。

表2-3 位运算符

5.逻辑运算符

逻辑运算符是一组用于执行布尔逻辑运算的运算符。它们主要用于处理布尔值(true或false),并根据逻辑运算的结果返回相应的布尔值。逻辑运算符及其说明如表2-4所示。

表2-4 逻辑运算符

2.3.5 语句

在ArkTS编程中,语句是执行某个操作或定义某种行为的基本代码单元,是构成程序的基本构件之一。语句可以独立完成特定的功能或操作。不同编程语言支持不同类型的语句,以下是ArkTS中一些常见的语句类型。

1.if语句

if语句用于根据逻辑条件选择性地执行不同的代码块。当逻辑条件为真(true)时,执行对应的语句;否则,执行else语句(如果存在)。

if语句的语法如下:

if (condition1) {
  // 语句1
} else if (condition2) {
  // 语句2
} else {
  // else语句
}

else部分还可以包含嵌套的if语句。条件表达式可以是任何类型,但非布尔类型会进行隐式类型转换。

● 真值(转换后为true的值):非空字符串、非零数字、对象、数组等。

● 假值(转换后为false的值):false、0、""(空字符串)、null、undefined和NaN。

条件表达式中隐式类型转换的示例如文件2-10所示。

文件2-10 条件表达式中的隐式类型转换

2.switch语句

当需要处理多个条件分支时,if-else语句可能显得冗长且不易阅读。此时,可以使用switch语句来简化逻辑。

switch语句的语法如下:

switch (expression) {
  case label1:
    // 如果label1匹配,则执行
    // ...
    // 语句1
    // ...
    break; // 可省略
  case label2:
  case label3:
    // 如果label2或label3匹配,则执行
    // ...
    // 语句23
    // ...
    break; // 可省略
  default:
    // 默认语句
}

如果switch表达式的值与某个case后面的label值匹配,则执行相应的语句块。Switch语句用法的示例代码如文件2-11所示。

文件2-11 switch用法的示例代码

let n = 2;
switch (n) {
  case 1:
    console.log('周一');
    break;
  case 2:
    console.log('周二');
    break;
  case 3:
    console.log('周三');
  default:
    console.log('做三休四')
}

执行上述代码时,因为变量n的值是2,所以switch语句会匹配到case 2,打印出“周二”,然后退出switch语句。

如果没有任何一个label值与表达式的值相匹配,并且switch具有default语句,那么程序会执行default语句对应的代码块,如文件2-12所示。

文件2-12 switch中default语句用法的示例代码

let n = 5;
switch (n) {
  case 1:
    console.log('周一');
    break;
  case 2:
    console.log('周二');
    break;
  case 3:
    console.log('周三');
  default:
    console.log('做三休四');
}

执行上述代码,因为变量n的值是5,switch语句中没有能匹配的case,所以程序会执行default分支,打印出“做三休四”。

break语句(可选)允许跳出switch语句并继续执行switch之后的语句。如果缺少break语句,程序将继续执行switch中的下一个label分支的代码块,如文件2-13所示。

文件2-13 switch中break语句用法的示例代码

let n = 1;
switch (n) {
  case 1:
    console.log('周一');
  case 2:
    console.log('周二');
    break;
  case 3:
    console.log('周三');
  default:
    console.log('做三休四');
}

执行上述代码,由于变量n的值为1,程序首先匹配到case1,打印“周一”。因为case 1分支中缺少break语句,程序继续执行case 2分支,所以会接着打印出“周二”。

3.条件表达式

条件表达式的语法如下:

condition ? expression1 : expression2

如果condition为真,则使用expression1作为该表达式的结果;否则使用expression2。条件表达式的示例代码如下:

let isValid = Math.random() > 0.5 ? true : false;
let message = isValid ? 'Valid' : 'Failed';
console.log(message);

上述代码解释如下:

● let isValid = Math.random() > 0.5 ? true : false;:Math.random()用于生成一个在0(包含)和1(不包含)之间的随机浮点数。如果生成的随机浮点数数大于0.5,则返回true,否则返回false。

● let message = isValid ? 'Valid' : 'Failed';:根据isValid的值来决定message的内容,如果isValid为true,则message被赋值为'Valid';否则message被赋值为'Failed'。

4.for语句

for语句用于重复执行代码,直到循环条件不再满足为止。for语句的语法如下:

for ([init]; [condition]; [update]) {
  statements
}

for语句的执行流程如下:

(1)执行init表达式(如果有)。此表达式通常用于初始化循环计数器。

(2)计算condition。如果它的值为真,则执行循环体内的语句(statements);如果它的值为假,则终止for循环。

(3)执行循环体内的语句(statements)。

(4)如果存在update表达式,则执行该表达式。

(5)回到第(2)步。

for语句用法的示例代码如文件2-14所示。

文件2-14 for语句用法的示例代码

let sum = 0;
for (let i = 0; i < 10; i += 2) {
  sum += i;
}
console.log(sum.toString());

上述代码是一个for循环,循环的目的是从i=0开始累加,每循环一次,i的值加2,直到i的值达到或超过10。最终输出结果为累加值。

5.for-of语句

for-of语句用于遍历数组或字符串,语法如下:

for (forVar of expression) {
  statements
}

其中:

● forVar是一个循环变量,用于在每次迭代中接收expression中的当前值。

● expression是一个可迭代对象(iterable),包括数组、字符串、集合(Set)、映射(Map)等。for…of循环将遍历这个可迭代对象中的每个元素。

● statements是每次迭代执行的代码块。可以在这里编写任意需要执行的逻辑。

for-of用法的示例代码如文件2-15所示。

文件2-15 for-of用法的示例代码

for (let ch of 'a string object') {
  if (ch != ' ') {
    console.log(ch);
  } else {
    console.log('空格');
  }
}

这段代码的主要功能是遍历字符串“a string object”,并对每个字符进行判断。如果是非空格字符,则直接输出字符;如果是空格字符,则输出“空格”。

6.while语句

while语句是一种常见的控制流程结构,用于重复执行一段代码,直到不满足某个条件为止。

while语句的语法如下:

while (condition) {
  statements
}

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

while语句用法的示例代码如文件2-16所示。

文件2-16 while语句用法的示例代码

7.do-while语句

do-while循环是一种先执行后判断的循环结构。这意味着会先执行一次循环体,再检查循环条件是否为真。如果条件为真,则继续执行循环体内的代码;如果条件为假,则停止循环。

do-while语句的语法如下:

do {
  statements
} while (condition);

在上述语法格式中,condition一个布尔表达式,用来判断是否继续执行循环。

do-while语句用法的示例代码如文件2-17所示。

文件2-17 do-while语句用法的示例代码

8.break语句

break语句用于终止循环或switch。break语句可以立即结束当前循环或跳出当前switch,继续执行后续代码。break语句用法的示例代码如文件2-18所示。

文件2-18 break语句用法的示例代码

如果break语句后带有标识符(label),则会将控制流转移到该标识符所标记的语句块之外,示例代码如文件2-19所示。

文件2-19 带有标识符的break语句用法的示例代码

9.continue语句

continue语句会停止当前循环迭代的执行,并将控制传递给下一个迭代。类似于你每天都跑步,某天身体不舒服,暂停一天,第二天继续。这种逻辑可以使用continue来实现。

continue语句用法的示例代码如文件2-20所示。

文件2-20 continue语句用法的示例代码

for (let i = 0; i < 7; i++) {
  if (i == 3) {
    console.log(`周${i + 1}不舒服,明天继续`)
    continue ;    // 跳过本次循环,进入下一次迭代
  }
  console.log(`周${i + 1}跑步去了`);
}
10.throw和try语句

throw语句用于抛出异常或错误,其语法如下:

throw new Error('this error');

try语句用于捕获和处理异常或错误,其语法如下:

try {
  // 可能发生异常的语句块
} catch (e) {
  // 异常处理
}

在文件2-21所示的示例中,throw和try语句用于处理除数为0的错误。

文件2-21 throw和try用法的示例代码

throw和try语句支持finally语句,finally的作用是不管try语句块中的代码是否抛出异常,finally语句块中的代码都会执行。通常在finally语句块中执行资源释放操作,例如关闭文件或释放内存等操作,以确保程序在正常完成或出现异常后不会占用不再需要的资源。

finally语句用法的示例代码如文件2-22所示。

文件2-22 finally语句用法的示例代码

另外,即使没有catch语句块,finally语句块仍然会执行,它的示例代码如文件2-23所示。

文件2-23 没有catch的finally语句用法的示例代码

function processfinallywithoutcatch(a: number, b: number): void {
  try {
   // 该语句可能抛出异常,使用try-catch语句块
   let res = divide(a, b);
   // 如果没有异常,则执行到这一句
   // 否则不执行
   console.log('result: ' + res);
  } finally {
   // 无论是否发生异常,该语句块都会执行
   console.log('执行结束')
  }
}

processfinallywithoutcatch(4, 0)

在上述代码中,即便try语句块抛出异常,程序仍会执行finally语句块中的代码,也就是依然会打印出“执行结束”,如图2-12所示。

图2-12 没有catch的finally语句的执行结果

2.4 本章小结

本章详细介绍了ArkTS语言及其在开发和测试中的应用,并讲解了ArkTS的基本语法规则。

1.ArkTS的特点与优势

ArkTS是HarmonyOS NEXT首选的应用开发语言,它在TypeScript的基础上进行了扩展。ArkTS强制使用静态类型,确保变量类型在编译时确定,从而提高代码的正确性和性能。ArkTS禁止运行时改变对象布局,限制运算符的语义,并不支持结构类型(Structural Typing)。这些特点共同作用,显著提高了程序的执行效率和稳定性。

在UI开发中,ArkTS扩展了声明式UI描述、自定义组件以及动态扩展UI元素的能力,提供了多维度的状态管理机制和强大的渲染控制能力。此外,ArkTS兼容TypeScript和JavaScript生态,开发者可以灵活使用TypeScript和JavaScript进行开发或复用现有代码。

2.DevEco Studio的使用与测试

本章还介绍了如何在DevEco Studio中使用arkxtest自动化测试框架进行单元测试和UI测试。创建新工程并编写单元测试脚本时,需要完成导入依赖包、编写测试代码和调用断言接口等步骤。通过自动化测试框架,可以实现对系统或应用接口的单元测试,以及基于界面操作的UI测试。在测试执行后,开发者可在DevEco Studio中查看测试结果。

3.基本语法规则

ArkTS的基本语法规则包括变量和常量的声明、自动类型推断、类型定义、运算符和语句。

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

(2)常量声明:使用const关键字声明只读常量,常量只能被赋值一次。

(3)自动类型推断:如果声明包含初始值,则类型可以自动推断,无须显式指定。

(4)类型定义:包括number、boolean、string、void、Object、array、enum、union和aliases等类型。

(5)运算符:包括赋值运算符、比较运算符、算术运算符、位运算符和逻辑运算符。

(6)语句:包括if语句、switch语句、条件表达式、for语句、for-of语句、while语句和do-while语句。

通过这些基本语法规则,开发者可以使用ArkTS编写高效、稳定的代码,并结合DevEco Studio进行测试,以确保代码质量和应用性能。

2.5 本章习题

(1)ArkTS的核心特性有哪些?

(2)如何在DevEco Studio中新建一个测试项目?

(3)在ArkTS中如何声明变量和常量?

(4)在ArkTS中有哪些常见的运算符?

(5)如何在ArkTS中进行类型推断? F5GPlM3v2oS0MELPaNTe0RFa1BxbomsiHhOfUt777MV2zX1yI7cuVRUBEE0YiUnf

点击中间区域
呼出菜单
上一章
目录
下一章
×