2 第1章 ArkTS高级语法与编程范式
HarmonyOS应用开发者高级认证教程
3 第1章 ArkTS高级语法与编程范式
3.1 学习目标
完成本章学习后,你将能够:
- 深入理解ArkTS与TypeScript的关系、设计理念及约束差异
- 掌握ArkTS高级类型系统,包括泛型约束、条件类型、装饰器等
- 熟练运用异步编程模式,包括Promise高级用法、TaskPool和Worker线程
- 理解并应用函数式编程范式,包括高阶函数、闭包、柯里化等
- 掌握模块系统与工程化最佳实践
- 具备高级错误处理与调试能力
3.2 1.1 ArkTS与TypeScript的关系和区别
3.2.1 1.1.1 ArkTS的设计理念
ArkTS是华为基于TypeScript扩展开发的声明式UI编程语言,是HarmonyOS应用开发的主力语言。它在继承TypeScript强大类型系统的基础上,针对HarmonyOS平台做了以下关键设计:
设计目标:
- 简洁性:减少代码量,提高开发效率
- 高性能:通过编译时优化和静态类型约束,实现更好的运行时性能
- 声明式UI:提供原生的声明式UI构建能力
- 安全可控:通过更严格的类型检查减少运行时错误
ArkTS的核心约束:
// ArkTS不允许使用any类型(TypeScript中的"逃逸舱口"被禁用)
// 以下代码在ArkTS中会报错:
// let value: any = "hello" // 编译错误!
// 必须使用明确的类型声明
let value: string = "hello"
let count: number = 42
let isValid: boolean = true
// 不允许使用联合类型中包含any的情况
// let mixed: string | any // 编译错误!
// 必须使用unknown替代需要动态类型的场景
let dynamic: unknown = "hello"
if (typeof dynamic === 'string') {
// 类型收窄后可以安全使用
let str: string = dynamic
}ArkTS对TypeScript的限制:
// 1. 禁止动态属性访问
interface User {
name: string
age: number
}
let user: User = { name: "张三", age: 25 }
// user["name"] // 在ArkTS中不推荐使用,应使用点号访问
let userName: string = user.name // 推荐方式
// 2. 禁止在运行时改变对象结构
// 不能动态添加属性
// user.phone = "123456" // 编译错误
// 3. 函数参数必须声明类型
function greet(name: string, age: number): string {
return `你好,${name},你今年${age}岁`
}
// 4. 不允许使用eval()
// eval("console.log('hello')") // 编译错误!
// 5. 不允许使用with语句
// with (obj) { ... } // 编译错误!3.2.2 1.1.2 静态类型检查的增强
ArkTS在编译阶段执行更严格的类型检查,以确保应用的质量和性能:
// 1. 严格的函数返回类型推断
function calculateTotal(price: number, quantity: number): number {
return price * quantity
}
// 2. 枚举类型的严格使用
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
function move(dir: Direction): void {
switch (dir) {
case Direction.Up:
console.log("向上移动")
break
case Direction.Down:
console.log("向下移动")
break
case Direction.Left:
console.log("向左移动")
break
case Direction.Right:
console.log("向右移动")
break
// ArkTS要求switch语句必须穷举所有枚举值
// 或者提供default分支
}
}
// 3. 严格的null检查
// ArkTS默认启用严格空检查
let name: string | null = null
// let len: number = name.length // 编译错误!name可能为null
// 必须使用可选链或空值合并运算符
let len: number = name?.length ?? 0
console.log(`名字长度: ${len}`)
// 4. 类型断言的限制
let unknownValue: unknown = "hello"
// let str: string = unknownValue as string // ArkTS限制使用as断言
// 推荐使用类型守卫
if (typeof unknownValue === 'string') {
let str: string = unknownValue // 安全的类型收窄
console.log(str.toUpperCase())
}3.2.3 1.1.3 ArkTS对TypeScript的扩展
ArkTS在TypeScript基础上增加了以下扩展能力:
// 1. 声明式UI扩展 - 装饰器语法
@Component
struct MyComponent {
@State message: string = "Hello HarmonyOS"
build() {
Column() {
Text(this.message)
.fontSize(24)
.fontWeight(FontWeight.Bold)
Button("点击更新")
.onClick(() => {
this.message = "Hello World"
})
}
}
}
// 2. 自定义组件装饰器
@Observed
class UserModel {
name: string = ""
age: number = 0
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
// 3. 入口组件装饰器
@Entry
@Component
struct Index {
@State counter: number = 0
build() {
Column() {
Text(`计数器: ${this.counter}`)
.fontSize(30)
Row() {
Button("+1")
.onClick(() => { this.counter++ })
Button("-1")
.onClick(() => { this.counter-- })
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
// 4. Builder装饰器 - 可复用的UI构建函数
@Component
struct ListComponent {
@Builder itemBuilder(title: string, subtitle: string) {
Row() {
Column() {
Text(title).fontSize(18).fontWeight(FontWeight.Medium)
Text(subtitle).fontSize(14).fontColor('#666666')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
}
build() {
List() {
ListItem() { this.itemBuilder("项目一", "这是描述信息") }
ListItem() { this.itemBuilder("项目二", "这是另一条描述") }
ListItem() { this.itemBuilder("项目三", "更多信息") }
}
.width('100%')
.height('100%')
}
}3.3 1.2 高级类型系统
3.3.1 1.2.1 联合类型与交叉类型
联合类型(Union Types)和交叉类型(Intersection Types)是ArkTS类型系统中的高级特性:
// 联合类型 - 表示值可以是多种类型之一
type StringOrNumber = string | number
function formatValue(value: StringOrNumber): string {
if (typeof value === 'string') {
return value.toUpperCase()
} else {
return value.toFixed(2)
}
}
// 交叉类型 - 合并多个类型
interface HasName {
name: string
}
interface HasAge {
age: number
}
interface HasEmail {
email: string
}
// 交叉类型组合多个接口
type Person = HasName & HasAge & HasEmail
let person: Person = {
name: "李四",
age: 30,
email: "lisi@example.com"
}
// 实际应用场景:组件属性合并
interface BaseProps {
id: string
className?: string
}
interface ClickableProps {
onClick: () => void
}
interface StyleProps {
color: string
fontSize: number
}
// 按钮组件需要同时具备基础属性、可点击属性和样式属性
type ButtonProps = BaseProps & ClickableProps & StyleProps
let buttonConfig: ButtonProps = {
id: "btn-submit",
className: "primary",
onClick: () => { console.log("按钮被点击") },
color: "#FF0000",
fontSize: 16
}3.3.2 1.2.2 类型守卫与类型收窄
类型守卫是安全处理联合类型的关键机制:
// 1. typeof类型守卫
function processInput(input: string | number | boolean): string {
if (typeof input === 'string') {
// 此处input被收窄为string类型
return input.toUpperCase()
} else if (typeof input === 'number') {
// 此处input被收窄为number类型
return input.toFixed(2)
} else {
// 此处input被收窄为boolean类型
return input ? "是" : "否"
}
}
// 2. in操作符类型守卫
interface Fish {
swim: () => void
name: string
}
interface Bird {
fly: () => void
name: string
}
function move(animal: Fish | Bird): void {
if ('swim' in animal) {
// animal被收窄为Fish类型
animal.swim()
} else {
// animal被收窄为Bird类型
animal.fly()
}
}
// 3. 自定义类型守卫(类型谓词)
interface SuccessResult {
code: 200
data: string
}
interface ErrorResult {
code: 400 | 500
message: string
}
type ApiResult = SuccessResult | ErrorResult
// 自定义类型守卫函数
function isSuccess(result: ApiResult): result is SuccessResult {
return result.code === 200
}
function handleResult(result: ApiResult): void {
if (isSuccess(result)) {
// result被收窄为SuccessResult
console.log(`数据: ${result.data}`)
} else {
// result被收窄为ErrorResult
console.log(`错误: ${result.message}`)
}
}
// 4. instanceof类型守卫
class NetworkError extends Error {
statusCode: number
constructor(message: string, statusCode: number) {
super(message)
this.statusCode = statusCode
}
}
class TimeoutError extends Error {
timeout: number
constructor(message: string, timeout: number) {
super(message)
this.timeout = timeout
}
}
function handleError(error: NetworkError | TimeoutError): string {
if (error instanceof NetworkError) {
return `网络错误,状态码: ${error.statusCode}`
} else {
return `请求超时,超时时间: ${error.timeout}ms`
}
}3.3.3 1.2.3 泛型的高级用法
泛型是实现代码复用和类型安全的核心工具:
// 1. 泛型约束
interface HasLength {
length: number
}
// 泛型约束:T必须有length属性
function logLength<T extends HasLength>(value: T): void {
console.log(`长度: ${value.length}`)
}
logLength("hello") // string有length属性
logLength([1, 2, 3]) // Array有length属性
// logLength(123) // 编译错误!number没有length属性
// 2. 泛型约束 - 键约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
interface Product {
id: number
name: string
price: number
}
let product: Product = { id: 1, name: "手机", price: 2999 }
let productName: string = getProperty(product, "name") // 类型安全
let productPrice: number = getProperty(product, "price") // 类型安全
// getProperty(product, "invalid") // 编译错误!"invalid"不是Product的键
// 3. 条件类型
type IsString<T> = T extends string ? true : false
type Result1 = IsString<string> // true
type Result2 = IsString<number> // false
// 条件类型实际应用:API响应处理
type ApiResponse<T> = T extends string
? { text: T }
: T extends number
? { value: T }
: { data: T }
type StringResponse = ApiResponse<string> // { text: string }
type NumberResponse = ApiResponse<number> // { value: number }
type ObjectResponse = ApiResponse<Product> // { data: Product }
// 4. 泛型工具类型
// 实现Partial - 将所有属性变为可选
type MyPartial<T> = {
[K in keyof T]?: T[K]
}
// 实现Required - 将所有属性变为必需
type MyRequired<T> = {
[K in keyof T]-?: T[K]
}
// 实现Pick - 从类型中选取部分属性
type MyPick<T, K extends keyof T> = {
[P in K]: T[P]
}
// 实现Omit - 从类型中排除部分属性
type MyOmit<T, K extends keyof T> = {
[P in Exclude<K, keyof T> | Exclude<keyof T, K>]: T[P]
}
// 实际应用
type ProductSummary = MyPick<Product, "id" | "name">
// 等价于 { id: number; name: string }
type ProductUpdate = MyPartial<MyOmit<Product, "id">>
// 等价于 { name?: string; price?: number }
// 5. 泛型类
class Stack<T> {
private items: T[] = []
push(item: T): void {
this.items.push(item)
}
pop(): T | undefined {
return this.items.pop()
}
peek(): T | undefined {
return this.items[this.items.length - 1]
}
isEmpty(): boolean {
return this.items.length === 0
}
size(): number {
return this.items.length
}
}
// 使用泛型类
let numberStack = new Stack<number>()
numberStack.push(1)
numberStack.push(2)
numberStack.push(3)
let top: number | undefined = numberStack.pop() // 3
let stringStack = new Stack<string>()
stringStack.push("Hello")
stringStack.push("World")3.3.4 1.2.4 装饰器与元编程
装饰器是ArkTS中实现元编程的重要手段,尤其在UI框架中广泛应用:
// 1. 类装饰器 - 用于类的声明
function logClass(target: Function): void {
console.log(`类被创建: ${target.name}`)
}
// 2. 属性装饰器
function logProperty(target: Object, propertyKey: string): void {
console.log(`属性: ${propertyKey}`)
}
// 3. 方法装饰器
function logMethod(
target: Object,
propertyKey: string,
descriptor: PropertyDescriptor
): PropertyDescriptor {
const originalMethod = descriptor.value
descriptor.value = function (...args: Object[]): Object {
console.log(`调用方法 ${propertyKey},参数: ${JSON.stringify(args)}`)
const result = originalMethod.apply(this, args)
console.log(`方法 ${propertyKey} 返回: ${JSON.stringify(result)}`)
return result
}
return descriptor
}
// 4. 实际应用场景:HarmonyOS中的状态管理装饰器
// @Observed 装饰器使类具备观察能力
@Observed
class TaskItem {
title: string
completed: boolean
priority: number
constructor(title: string, priority: number = 0) {
this.title = title
this.completed = false
this.priority = priority
}
toggle(): void {
this.completed = !this.completed
}
}
// @ObservedV2 是V2版本的状态管理装饰器
@ObservedV2
class ShoppingCart {
@Trace items: string[] = []
@Trace totalPrice: number = 0
addItem(item: string, price: number): void {
this.items.push(item)
this.totalPrice += price
}
removeItem(index: number): void {
this.items.splice(index, 1)
}
}
// 5. 自定义装饰器实现缓存功能
function memoize(
target: Object,
propertyKey: string,
descriptor: PropertyDescriptor
): PropertyDescriptor {
const originalMethod = descriptor.value
const cache = new Map<string, Object>()
descriptor.value = function (...args: Object[]): Object {
const key = JSON.stringify(args)
if (cache.has(key)) {
return cache.get(key)
}
const result = originalMethod.apply(this, args)
cache.set(key, result)
return result
}
return descriptor
}3.4 1.3 异步编程深入
3.4.1 1.3.1 Promise链式调用与错误处理
Promise是异步编程的基础,掌握其高级用法对于构建复杂应用至关重要:
// 1. Promise链式调用的最佳实践
interface UserInfo {
id: number
name: string
email: string
}
interface UserOrders {
userId: number
orders: string[]
}
interface OrderDetail {
orderId: string
amount: number
status: string
}
// 模拟API调用
function fetchUserInfo(userId: number): Promise<UserInfo> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id: userId, name: "张三", email: "zhangsan@example.com" })
}, 1000)
})
}
function fetchUserOrders(userId: number): Promise<UserOrders> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ userId: userId, orders: ["ORD001", "ORD002", "ORD003"] })
}, 800)
})
}
function fetchOrderDetail(orderId: string): Promise<OrderDetail> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ orderId: orderId, amount: 99.9, status: "已完成" })
}, 500)
})
}
// 链式调用 - 获取用户信息 -> 获取订单列表 -> 获取第一个订单详情
function getUserFirstOrder(userId: number): Promise<OrderDetail> {
return fetchUserInfo(userId)
.then((userInfo: UserInfo): Promise<UserOrders> => {
console.log(`获取到用户信息: ${userInfo.name}`)
return fetchUserOrders(userInfo.id)
})
.then((userOrders: UserOrders): Promise<OrderDetail> => {
if (userOrders.orders.length === 0) {
throw new Error("用户没有订单")
}
return fetchOrderDetail(userOrders.orders[0])
})
.catch((error: Error): Promise<OrderDetail> => {
console.error(`获取订单详情失败: ${error.message}`)
// 返回默认值或重新抛出错误
return Promise.reject(error)
})
}
// 2. 错误处理策略
// 策略一:在链的末尾统一处理
fetchUserInfo(1)
.then((info: UserInfo) => fetchUserOrders(info.id))
.then((orders: UserOrders) => {
console.log(`订单数量: ${orders.orders.length}`)
})
.catch((error: Error) => {
console.error(`统一错误处理: ${error.message}`)
})
.finally(() => {
console.log("请求完成,无论成功失败都会执行")
})
// 策略二:分层错误处理
async function loadDataWithRetry(
userId: number,
maxRetries: number = 3
): Promise<UserInfo> {
let lastError: Error = new Error("未知错误")
for (let attempt: number = 1; attempt <= maxRetries; attempt++) {
try {
let userInfo: UserInfo = await fetchUserInfo(userId)
console.log(`第${attempt}次尝试成功`)
return userInfo
} catch (error) {
lastError = error as Error
console.warn(`第${attempt}次尝试失败: ${lastError.message}`)
if (attempt < maxRetries) {
// 指数退避
await new Promise<void>((resolve) =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
)
}
}
}
throw lastError
}3.4.2 1.3.2 async/await高级模式
// 1. 并行执行多个异步操作
async function loadDashboardData(userId: number): Promise<void> {
// 并行请求 - 所有请求同时发出
let userInfoPromise: Promise<UserInfo> = fetchUserInfo(userId)
let ordersPromise: Promise<UserOrders> = fetchUserOrders(userId)
try {
// 等待所有并行请求完成
let [userInfo, orders]: [UserInfo, UserOrders] =
await Promise.all([userInfoPromise, ordersPromise])
console.log(`用户: ${userInfo.name}, 订单数: ${orders.orders.length}`)
} catch (error) {
console.error(`加载仪表板数据失败: ${(error as Error).message}`)
}
}
// 2. 串行与并行混合
async function processBatchData(userIds: number[]): Promise<OrderDetail[]> {
let allDetails: OrderDetail[] = []
for (let userId of userIds) {
// 每个用户的订单并行获取
let orders: UserOrders = await fetchUserOrders(userId)
let detailPromises: Promise<OrderDetail>[] =
orders.orders.map((id: string) => fetchOrderDetail(id))
let details: OrderDetail[] = await Promise.all(detailPromises)
allDetails = allDetails.concat(details)
}
return allDetails
}
// 3. 异步迭代器模式
async function* asyncDataGenerator(count: number): AsyncGenerator<number> {
for (let i: number = 0; i < count; i++) {
// 模拟异步数据获取
await new Promise<void>((resolve) => setTimeout(resolve, 100))
yield i
}
}
// 使用异步迭代器
async function processData(): Promise<void> {
for await (let value of asyncDataGenerator(5)) {
console.log(`处理数据: ${value}`)
}
}
// 4. 超时控制
async function fetchWithTimeout<T>(
promise: Promise<T>,
timeoutMs: number
): Promise<T> {
let timeoutPromise: Promise<T> = new Promise<T>((_, reject) => {
setTimeout(() => {
reject(new Error(`请求超时 (${timeoutMs}ms)`))
}, timeoutMs)
})
return Promise.race([promise, timeoutPromise])
}
// 使用超时控制
async function loadWithTimeout(): Promise<void> {
try {
let userInfo: UserInfo = await fetchWithTimeout(
fetchUserInfo(1),
3000 // 3秒超时
)
console.log(`加载成功: ${userInfo.name}`)
} catch (error) {
console.error(`加载失败: ${(error as Error).message}`)
}
}3.4.3 1.3.3 并发控制
// 1. Promise.all - 所有成功才成功
async function fetchAllUserData(userId: number): Promise<void> {
try {
let results: [UserInfo, UserOrders] = await Promise.all([
fetchUserInfo(userId),
fetchUserOrders(userId)
])
console.log(`用户信息: ${results[0].name}`)
console.log(`订单数量: ${results[1].orders.length}`)
} catch (error) {
// 任何一个Promise失败,整体失败
console.error(`获取数据失败: ${(error as Error).message}`)
}
}
// 2. Promise.allSettled - 等待所有完成,不论成功失败
async function fetchAllSettled(): Promise<void> {
let promises: Promise<UserInfo>[] = [
fetchUserInfo(1),
fetchUserInfo(2),
fetchUserInfo(3)
]
let results: PromiseSettledResult<UserInfo>[] =
await Promise.allSettled(promises)
for (let result of results) {
if (result.status === 'fulfilled') {
console.log(`成功: ${result.value.name}`)
} else {
console.log(`失败: ${result.reason}`)
}
}
}
// 3. Promise.race - 取最先完成的
async function fetchFastest(): Promise<UserInfo> {
// 从多个数据源获取,使用最快的
return Promise.race([
fetchUserInfo(1),
new Promise<UserInfo>((_, reject) =>
setTimeout(() => reject(new Error("超时")), 5000)
)
])
}
// 4. 并发限制器 - 控制同时执行的任务数量
class ConcurrencyLimiter {
private concurrency: number
private running: number = 0
private queue: Array<() => void> = []
constructor(concurrency: number) {
this.concurrency = concurrency
}
async execute<T>(task: () => Promise<T>): Promise<T> {
while (this.running >= this.concurrency) {
await new Promise<void>((resolve) => this.queue.push(resolve))
}
this.running++
try {
return await task()
} finally {
this.running--
if (this.queue.length > 0) {
let next = this.queue.shift()
if (next) next()
}
}
}
}
// 使用并发限制器
async function batchProcess(): Promise<void> {
let limiter = new ConcurrencyLimiter(3) // 最多3个并发
let tasks: Promise<void>[] = []
for (let i: number = 0; i < 10; i++) {
let userId = i
tasks.push(
limiter.execute(async () => {
let info: UserInfo = await fetchUserInfo(userId)
console.log(`处理完成: ${info.name}`)
})
)
}
await Promise.all(tasks)
console.log("所有任务处理完成")
}3.4.4 1.3.4 TaskPool和Worker线程
HarmonyOS提供了TaskPool和Worker两种多线程方案:
// 1. TaskPool - 推荐的高性能并发方案
import taskpool from '@ohos.taskpool'
// 定义可以在TaskPool中执行的任务
@Concurrent
function computeHeavyTask(data: number[]): number {
let sum: number = 0
for (let i: number = 0; i < data.length; i++) {
sum += data[i] * data[i]
}
return sum
}
// 在组件中使用TaskPool
@Component
struct TaskPoolExample {
@State result: string = "等待计算..."
@State isLoading: boolean = false
async startComputation(): Promise<void> {
this.isLoading = true
let data: number[] = []
for (let i: number = 0; i < 10000; i++) {
data.push(i)
}
try {
// 创建TaskPool任务
let task = new taskpool.Task(computeHeavyTask, data)
// 执行任务
let result: number = await taskpool.execute(task) as number
this.result = `计算结果: ${result}`
} catch (error) {
this.result = `计算失败: ${(error as Error).message}`
} finally {
this.isLoading = false
}
}
build() {
Column() {
Text(this.result).fontSize(18)
Button("开始计算")
.enabled(!this.isLoading)
.onClick(() => { this.startComputation() })
}
}
}
// 2. TaskPool分组执行
@Concurrent
function processChunk(chunk: number[], offset: number): number {
let sum: number = 0
for (let i: number = 0; i < chunk.length; i++) {
sum += chunk[i]
}
return sum
}
async function parallelProcess(data: number[], chunkSize: number): Promise<number> {
let group = new taskpool.TaskGroup()
for (let i: number = 0; i < data.length; i += chunkSize) {
let chunk: number[] = data.slice(i, Math.min(i + chunkSize, data.length))
group.addTask(new taskpool.Task(processChunk, chunk, i))
}
// 并行执行所有分块任务
let results: number[] = await taskpool.execute(group) as number[]
let total: number = 0
for (let r of results) {
total += r
}
return total
}
// 3. Worker线程 - 适合长期运行的后台任务
import worker from '@ohos.worker'
// worker线程文件 (worker/MyWorker.ts)
// import worker from '@ohos.worker'
//
// const workerPort = worker.workerPort
//
// workerPort.onmessage = (event: MessageEvents) => {
// const data = event.data
// // 执行耗时操作
// const result = heavyComputation(data)
// workerPort.postMessage(result)
// }
//
// function heavyComputation(data: number[]): number {
// return data.reduce((sum: number, val: number) => sum + val, 0)
// }
// 在主线程中使用Worker
@Component
struct WorkerExample {
@State workerResult: string = "等待Worker结果..."
private myWorker: worker.ThreadWorker | null = null
aboutToAppear(): void {
// 创建Worker线程
this.myWorker = new worker.ThreadWorker(
'entry/ets/workers/MyWorker.ets'
)
// 接收Worker消息
this.myWorker.onmessage = (e: MessageEvents) => {
this.workerResult = `Worker计算结果: ${e.data}`
}
}
aboutToDisappear(): void {
// 销毁Worker线程
if (this.myWorker) {
this.myWorker.terminate()
this.myWorker = null
}
}
build() {
Column() {
Text(this.workerResult).fontSize(18)
Button("发送数据到Worker")
.onClick(() => {
if (this.myWorker) {
this.myWorker.postMessage([1, 2, 3, 4, 5])
}
})
}
}
}
// 4. TaskPool vs Worker 选择指南
// TaskPool适用场景:
// - 计算密集型任务
// - 不需要与主线程频繁通信
// - 任务可以并行化
// - 短期运行的任务
// Worker适用场景:
// - 需要长期运行的后台任务
// - 需要与主线程频繁通信
// - 需要维护后台状态
// - 需要独立的执行环境3.5 1.4 函数式编程范式
3.5.1 1.4.1 高阶函数
高阶函数是指接受函数作为参数或返回函数作为结果的函数:
// 1. 函数作为参数
function applyOperation(
values: number[],
operation: (x: number) => number
): number[] {
return values.map(operation)
}
let numbers: number[] = [1, 2, 3, 4, 5]
let doubled: number[] = applyOperation(numbers, (x: number) => x * 2)
// [2, 4, 6, 8, 10]
let squared: number[] = applyOperation(numbers, (x: number) => x * x)
// [1, 4, 9, 16, 25]
// 2. 函数作为返回值
function createMultiplier(factor: number): (x: number) => number {
return (x: number): number => x * factor
}
let double = createMultiplier(2)
let triple = createMultiplier(3)
console.log(double(5)) // 10
console.log(triple(5)) // 15
// 3. 函数组合
function compose<A, B, C>(
f: (x: B) => C,
g: (x: A) => B
): (x: A) => C {
return (x: A): C => f(g(x))
}
// 使用示例
let addOne = (x: number): number => x + 1
let multiplyByTwo = (x: number): number => x * 2
let square = (x: number): number => x * x
// 组合函数:先加1,再乘2,再平方
let transform = compose(square, compose(multiplyByTwo, addOne))
console.log(transform(3)) // ((3+1)*2)^2 = 64
// 4. 管道操作
function pipe<A, B, C>(
f: (x: A) => B,
g: (x: B) => C
): (x: A) => C {
return (x: A): C => g(f(x))
}
// 数据处理管道
type Product = { name: string; price: number; category: string }
let products: Product[] = [
{ name: "手机", price: 2999, category: "电子" },
{ name: "电脑", price: 5999, category: "电子" },
{ name: "T恤", price: 99, category: "服装" },
{ name: "裤子", price: 199, category: "服装" },
{ name: "耳机", price: 599, category: "电子" },
]
// 使用函数式管道处理数据
let electronicsOver500: Product[] = products
.filter((p: Product): boolean => p.category === "电子")
.filter((p: Product): boolean => p.price > 500)
.sort((a: Product, b: Product): number => b.price - a.price)
console.log(electronicsOver500)
// [{ name: "电脑", price: 5999 }, { name: "手机", price: 2999 }]
// 5. 实际应用:事件处理函数工厂
function createDebouncedHandler(
handler: (value: string) => void,
delayMs: number
): (value: string) => void {
let timerId: number = -1
return (value: string): void => {
if (timerId !== -1) {
clearTimeout(timerId)
}
timerId = setTimeout(() => {
handler(value)
timerId = -1
}, delayMs)
}
}
// 在组件中使用防抖搜索
@Component
struct SearchComponent {
@State searchText: string = ""
private debouncedSearch: (value: string) => void =
createDebouncedHandler((query: string) => {
console.log(`搜索: ${query}`)
// 执行搜索逻辑
}, 300)
build() {
Column() {
TextInput({ placeholder: "搜索..." })
.onChange((value: string) => {
this.searchText = value
this.debouncedSearch(value)
})
}
}
}3.5.2 1.4.2 闭包与词法作用域
// 1. 闭包的基本概念
function createCounter(): () => number {
let count: number = 0 // 被闭包捕获的变量
return (): number => {
count++
return count
}
}
let counter1 = createCounter()
console.log(counter1()) // 1
console.log(counter1()) // 2
console.log(counter1()) // 3
let counter2 = createCounter() // 独立的闭包实例
console.log(counter2()) // 1
// 2. 闭包实现数据私有化
function createBankAccount(initialBalance: number) {
let balance: number = initialBalance
let transactions: string[] = []
return {
deposit: (amount: number): void => {
if (amount <= 0) {
throw new Error("存款金额必须大于0")
}
balance += amount
transactions.push(`存入: ${amount}, 余额: ${balance}`)
},
withdraw: (amount: number): void => {
if (amount <= 0 || amount > balance) {
throw new Error("无效的取款金额")
}
balance -= amount
transactions.push(`取出: ${amount}, 余额: ${balance}`)
},
getBalance: (): number => balance,
getHistory: (): string[] => [...transactions]
}
}
let account = createBankAccount(1000)
account.deposit(500)
account.withdraw(200)
console.log(account.getBalance()) // 1300
console.log(account.getHistory())
// ["存入: 500, 余额: 1500", "取出: 200, 余额: 1300"]
// 3. 闭包在HarmonyOS中的应用
@Component
struct TimerComponent {
@State elapsedTime: number = 0
@State isRunning: boolean = false
private timerId: number = -1
private startTime: number = 0
private startTimer(): void {
this.isRunning = true
this.startTime = Date.now() - this.elapsedTime
// 使用闭包捕获this引用
this.timerId = setInterval(() => {
this.elapsedTime = Date.now() - this.startTime
}, 100)
}
private stopTimer(): void {
this.isRunning = false
if (this.timerId !== -1) {
clearInterval(this.timerId)
this.timerId = -1
}
}
private formatTime(ms: number): string {
let seconds: number = Math.floor(ms / 1000)
let minutes: number = Math.floor(seconds / 60)
let hours: number = Math.floor(minutes / 60)
seconds = seconds % 60
minutes = minutes % 60
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}
aboutToDisappear(): void {
this.stopTimer()
}
build() {
Column({ space: 20 }) {
Text(this.formatTime(this.elapsedTime))
.fontSize(48)
.fontWeight(FontWeight.Bold)
Row({ space: 20 }) {
Button(this.isRunning ? "暂停" : "开始")
.onClick(() => {
if (this.isRunning) {
this.stopTimer()
} else {
this.startTimer()
}
})
Button("重置")
.onClick(() => {
this.stopTimer()
this.elapsedTime = 0
})
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}3.5.3 1.4.3 柯里化与偏函数
// 1. 柯里化 - 将多参数函数转换为单参数函数链
function curry<T extends Function>(fn: Function): T {
return function curried(...args: Object[]): Function {
if (args.length >= fn.length) {
return fn.apply(this, args)
}
return function (...moreArgs: Object[]): Function {
return curried.apply(this, args.concat(moreArgs))
}
} as T
}
// 示例
function add(a: number, b: number, c: number): number {
return a + b + c
}
let curriedAdd = curry<(x: number) => (y: number) => (z: number) => number>(add)
console.log(curriedAdd(1)(2)(3)) // 6
// 2. 偏函数 - 固定部分参数
function createLogger(
prefix: string
): (level: string, message: string) => void {
return (level: string, message: string): void => {
console.log(`[${prefix}] [${level}] ${message}`)
}
}
let appLogger = createLogger("MyApp")
appLogger("INFO", "应用启动") // [MyApp] [INFO] 应用启动
appLogger("ERROR", "发生错误") // [MyApp] [ERROR] 发生错误
// 3. 实际应用:配置化组件
interface ComponentConfig {
theme: string
fontSize: number
padding: number
}
function createStyledComponent(defaultConfig: ComponentConfig) {
return (overrides: Partial<ComponentConfig>): ComponentConfig => {
return {
...defaultConfig,
...overrides
}
}
}
let defaultTheme = createStyledComponent({
theme: "light",
fontSize: 14,
padding: 16
})
// 创建特定场景的配置
let compactConfig: ComponentConfig = defaultTheme({ fontSize: 12, padding: 8 })
let largeConfig: ComponentConfig = defaultTheme({ fontSize: 18, padding: 24 })3.5.4 1.4.4 不可变数据模式
// 1. 使用readonly创建不可变类型
interface ReadonlyPoint {
readonly x: number
readonly y: number
}
let point: ReadonlyPoint = { x: 10, y: 20 }
// point.x = 30 // 编译错误!只读属性不能修改
// 2. 不可变数据操作 - 返回新对象而非修改原对象
class ImmutableList<T> {
private readonly items: ReadonlyArray<T>
constructor(items: T[] = []) {
this.items = [...items]
}
// 添加元素返回新实例
add(item: T): ImmutableList<T> {
return new ImmutableList([...this.items, item])
}
// 删除元素返回新实例
remove(index: number): ImmutableList<T> {
let newItems: T[] = [...this.items]
newItems.splice(index, 1)
return new ImmutableList(newItems)
}
// 更新元素返回新实例
update(index: number, item: T): ImmutableList<T> {
let newItems: T[] = [...this.items]
newItems[index] = item
return new ImmutableList(newItems)
}
get(index: number): T | undefined {
return this.items[index]
}
get size(): number {
return this.items.length
}
toArray(): T[] {
return [...this.items]
}
}
// 使用不可变列表
let list1 = new ImmutableList<number>([1, 2, 3])
let list2 = list1.add(4) // 新实例
let list3 = list2.update(0, 10) // 新实例
console.log(list1.toArray()) // [1, 2, 3] - 原列表不变
console.log(list2.toArray()) // [1, 2, 3, 4]
console.log(list3.toArray()) // [10, 2, 3, 4]
// 3. 不可变数据在状态管理中的应用
interface AppState {
readonly users: ReadonlyArray<string>
readonly loading: boolean
readonly error: string | null
}
// 纯函数更新状态
function addUser(state: AppState, user: string): AppState {
return {
...state,
users: [...state.users, user]
}
}
function setLoading(state: AppState, loading: boolean): AppState {
return { ...state, loading }
}
function setError(state: AppState, error: string | null): AppState {
return { ...state, error }
}
// 状态变更历史 - 利用不可变性实现时间旅行
class StateHistory<S> {
private history: S[] = []
private currentIndex: number = -1
push(state: S): void {
// 丢弃当前索引之后的历史
this.history = this.history.slice(0, this.currentIndex + 1)
this.history.push(state)
this.currentIndex = this.history.length - 1
}
undo(): S | undefined {
if (this.currentIndex > 0) {
this.currentIndex--
return this.history[this.currentIndex]
}
return undefined
}
redo(): S | undefined {
if (this.currentIndex < this.history.length - 1) {
this.currentIndex++
return this.history[this.currentIndex]
}
return undefined
}
current(): S | undefined {
return this.history[this.currentIndex]
}
}3.6 1.5 模块系统与工程化
3.6.1 1.5.1 ES Module规范
// 1. 命名导出
// math/Calculator.ts
export function add(a: number, b: number): number {
return a + b
}
export function subtract(a: number, b: number): number {
return a - b
}
export const PI: number = 3.14159265358979
// 2. 默认导出
// models/UserModel.ts
export default class UserModel {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
greet(): string {
return `你好,我是${this.name}`
}
}
// 3. 导入方式
// 命名导入
import { add, subtract, PI } from './math/Calculator'
// 默认导入
import UserModel from './models/UserModel'
// 命名空间导入
import * as MathUtils from './math/Calculator'
let result: number = MathUtils.add(1, 2)
// 4. 重命名导入导出
import { add as addition, subtract as subtraction } from './math/Calculator'
// 5. 重新导出
// utils/index.ts
export { add, subtract } from './math/Calculator'
export { default as UserModel } from './models/UserModel'
export * from './types'
// 6. 模块组织最佳实践
// services/ApiService.ts
export interface ApiConfig {
baseUrl: string
timeout: number
headers: Map<string, string>
}
export class ApiService {
private config: ApiConfig
constructor(config: ApiConfig) {
this.config = config
}
async get<T>(path: string): Promise<T> {
let url: string = `${this.config.baseUrl}${path}`
// ... 实现GET请求
return {} as T
}
async post<T>(path: string, data: Object): Promise<T> {
let url: string = `${this.config.baseUrl}${path}`
// ... 实现POST请求
return {} as T
}
}
// 创建工厂函数
export function createApiService(
baseUrl: string,
timeout: number = 5000
): ApiService {
let headers = new Map<string, string>()
headers.set("Content-Type", "application/json")
return new ApiService({ baseUrl, timeout, headers })
}3.6.2 1.5.2 循环依赖处理
// 循环依赖问题示例与解决方案
// 问题场景:
// A.ts 导入 B.ts,B.ts 又导入 A.ts -> 循环依赖
// 解决方案1:提取共享接口到独立模块
// types/SharedTypes.ts
export interface NodeData {
id: string
name: string
}
export interface NodeProcessor {
process(node: NodeData): void
}
// A.ts
import { NodeData, NodeProcessor } from './types/SharedTypes'
export class NodeA implements NodeProcessor {
process(node: NodeData): void {
console.log(`NodeA处理: ${node.name}`)
}
}
// B.ts
import { NodeData, NodeProcessor } from './types/SharedTypes'
export class NodeB implements NodeProcessor {
process(node: NodeData): void {
console.log(`NodeB处理: ${node.name}`)
}
}
// 解决方案2:依赖注入
// 定义接口
export interface ServiceA {
doSomething(): void
}
export interface ServiceB {
doAnother(): void
}
// 通过注入解决循环依赖
export class ServiceAImpl implements ServiceA {
private serviceB: ServiceB | null = null
setServiceB(serviceB: ServiceB): void {
this.serviceB = serviceB
}
doSomething(): void {
console.log("ServiceA执行")
this.serviceB?.doAnother()
}
}
export class ServiceBImpl implements ServiceB {
private serviceA: ServiceA | null = null
setServiceA(serviceA: ServiceA): void {
this.serviceA = serviceA
}
doAnother(): void {
console.log("ServiceB执行")
}
}3.6.3 1.5.3 动态导入
// 1. 动态导入 - 按需加载模块
async function loadFeatureModule(featureName: string): Promise<void> {
switch (featureName) {
case 'analytics':
let analytics = await import('./features/AnalyticsModule')
analytics.initialize()
break
case 'payment':
let payment = await import('./features/PaymentModule')
payment.setup()
break
default:
console.log(`未知功能: ${featureName}`)
}
}
// 2. 条件加载
async function loadPlatformSpecific(): Promise<Object> {
let platform: string = 'default'
// 根据平台动态加载
let module = await import(`./platform/${platform}`)
return module
}
// 3. 错误边界的动态导入
async function safeLoadModule(modulePath: string): Promise<Object | null> {
try {
let module = await import(modulePath)
return module
} catch (error) {
console.error(`模块加载失败: ${modulePath}`, error)
return null
}
}3.6.4 1.5.4 包管理与版本控制
// oh-package.json5 配置示例
/*
{
"name": "my-harmony-app",
"version": "1.0.0",
"description": "HarmonyOS应用",
"main": "",
"author": "",
"license": "Apache-2.0",
"dependencies": {
// 精确版本
"@ohos/axios": "2.1.0",
// 兼容版本范围
"@ohos/lottie": "^1.0.0",
// 本地模块引用
"my-library": "file:./libs/my-library"
},
"devDependencies": {
"@ohos/hypium": "1.0.6"
}
}
*/
// 版本管理最佳实践
// 1. 语义化版本控制 (SemVer)
// major.minor.patch
// 1.0.0 -> 1.0.1 (修复bug)
// 1.0.0 -> 1.1.0 (新增功能,向后兼容)
// 1.0.0 -> 2.0.0 (破坏性变更)
// 2. 锁文件管理
// oh-package-lock.json 记录精确版本
// 确保团队成员和CI环境使用相同版本
// 3. 本地HAR包管理
// 创建HAR包
// build-profile.json5中配置:
/*
{
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
]
},
{
"name": "common",
"srcPath": "./common",
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
]
}
]
}
*/3.7 1.6 错误处理与调试
3.7.1 1.6.1 try-catch-finally高级用法
// 1. 结构化错误处理
class Result<T> {
private constructor(
private readonly value: T | null,
private readonly error: Error | null,
private readonly isSuccess: boolean
) {}
static success<T>(value: T): Result<T> {
return new Result<T>(value, null, true)
}
static failure<T>(error: Error): Result<T> {
return new Result<T>(null, error, false)
}
get Value(): T {
if (!this.isSuccess || this.value === null) {
throw new Error("尝试获取失败结果的值")
}
return this.value
}
get Error(): Error {
if (this.isSuccess || this.error === null) {
throw new Error("尝试获取成功结果的错误")
}
return this.error
}
get IsSuccess(): boolean {
return this.isSuccess
}
map<U>(fn: (value: T) => U): Result<U> {
if (this.isSuccess && this.value !== null) {
return Result.success(fn(this.value))
}
return Result.failure<U>(this.error!)
}
flatMap<U>(fn: (value: T) => Result<U>): Result<U> {
if (this.isSuccess && this.value !== null) {
return fn(this.value)
}
return Result.failure<U>(this.error!)
}
}
// 使用Result模式
function parseJson(jsonString: string): Result<Object> {
try {
let parsed: Object = JSON.parse(jsonString)
return Result.success(parsed)
} catch (error) {
return Result.failure(new Error(`JSON解析失败: ${(error as Error).message}`))
}
}
let result: Result<Object> = parseJson('{"name": "张三"}')
if (result.IsSuccess) {
console.log("解析成功:", result.Value)
} else {
console.log("解析失败:", result.Error.message)
}
// 2. 资源清理模式
class ResourceHandler {
async withResource<T>(
acquire: () => Promise<T>,
use: (resource: T) => Promise<void>,
release: (resource: T) => Promise<void>
): Promise<void> {
let resource: T | null = null
try {
resource = await acquire()
await use(resource)
} catch (error) {
console.error("资源使用出错:", error)
throw error
} finally {
if (resource !== null) {
try {
await release(resource)
} catch (releaseError) {
console.error("资源释放失败:", releaseError)
}
}
}
}
}
// 3. 多重异常捕获
async function robustFetch(url: string): Promise<string> {
try {
let response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status}`)
}
return await response.text()
} catch (error) {
if (error instanceof TypeError) {
// 网络错误
throw new Error(`网络连接失败: ${url}`)
} else if (error instanceof Error) {
// 其他已知错误
throw error
} else {
// 未知错误
throw new Error(`未知错误: ${String(error)}`)
}
}
}3.7.2 1.6.2 自定义异常类
// 1. 异常层次结构
class AppError extends Error {
code: number
timestamp: number
context: Map<string, string>
constructor(message: string, code: number, context?: Map<string, string>) {
super(message)
this.name = "AppError"
this.code = code
this.timestamp = Date.now()
this.context = context ?? new Map<string, string>()
}
toJSON(): Object {
return {
name: this.name,
message: this.message,
code: this.code,
timestamp: this.timestamp,
context: Object.fromEntries(this.context)
}
}
}
class NetworkError extends AppError {
url: string
statusCode: number
constructor(message: string, url: string, statusCode: number) {
super(message, 1001)
this.name = "NetworkError"
this.url = url
this.statusCode = statusCode
}
}
class ValidationError extends AppError {
field: string
constraint: string
constructor(message: string, field: string, constraint: string) {
super(message, 2001)
this.name = "ValidationError"
this.field = field
this.constraint = constraint
}
}
class AuthenticationError extends AppError {
constructor(message: string) {
super(message, 3001)
this.name = "AuthenticationError"
}
}
class AuthorizationError extends AppError {
requiredPermission: string
constructor(message: string, requiredPermission: string) {
super(message, 3002)
this.name = "AuthorizationError"
this.requiredPermission = requiredPermission
}
}
// 2. 错误处理服务
class ErrorHandlingService {
private static instance: ErrorHandlingService | null = null
static getInstance(): ErrorHandlingService {
if (!ErrorHandlingService.instance) {
ErrorHandlingService.instance = new ErrorHandlingService()
}
return ErrorHandlingService.instance
}
handleError(error: unknown): void {
if (error instanceof NetworkError) {
this.handleNetworkError(error)
} else if (error instanceof ValidationError) {
this.handleValidationError(error)
} else if (error instanceof AuthenticationError) {
this.handleAuthError(error)
} else if (error instanceof AppError) {
this.handleAppError(error)
} else {
this.handleUnknownError(error)
}
}
private handleNetworkError(error: NetworkError): void {
console.error(`网络错误 [${error.statusCode}]: ${error.message}`)
console.error(`URL: ${error.url}`)
// 显示网络错误提示
}
private handleValidationError(error: ValidationError): void {
console.error(`验证错误 [${error.field}]: ${error.message}`)
console.error(`约束: ${error.constraint}`)
// 高亮错误字段
}
private handleAuthError(error: AuthenticationError): void {
console.error(`认证错误: ${error.message}`)
// 跳转到登录页
}
private handleAppError(error: AppError): void {
console.error(`应用错误 [${error.code}]: ${error.message}`)
}
private handleUnknownError(error: unknown): void {
console.error("未知错误:", error)
}
}3.7.3 1.6.3 全局异常捕获
// 1. 应用级全局异常处理
// EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'
import { window } from '@kit.ArkUI'
import { hilog } from '@kit.PerformanceAnalysisKit'
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'EntryAbility', '应用创建')
// 注册全局异常处理
this.registerGlobalErrorHandler()
}
private registerGlobalErrorHandler(): void {
// 捕获未处理的Promise异常
// 注意:ArkTS中通过context.getApplicationContext()获取应用上下文
let appContext = this.context.getApplicationContext()
// 注册应用级别错误回调
appContext.on('applicationState', {
onApplicationForeground: () => {
hilog.info(0x0000, 'EntryAbility', '应用进入前台')
},
onApplicationBackground: () => {
hilog.info(0x0000, 'EntryAbility', '应用进入后台')
}
})
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// 设置UI异常处理
windowStage.on('windowStageEvent', (event: number) => {
hilog.info(0x0000, 'EntryAbility', `窗口事件: ${event}`)
})
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'EntryAbility',
'加载页面失败: %{public}s', JSON.stringify(err))
return
}
hilog.info(0x0000, 'EntryAbility', '页面加载成功')
})
}
}
// 2. 错误日志收集器
class ErrorCollector {
private static errors: Array<{
error: string,
timestamp: number,
stack?: string
}> = []
private static maxSize: number = 100
static collect(error: unknown): void {
let errorInfo: string
let stack: string | undefined
if (error instanceof Error) {
errorInfo = error.message
stack = error.stack
} else {
errorInfo = String(error)
}
ErrorCollector.errors.push({
error: errorInfo,
timestamp: Date.now(),
stack: stack
})
// 限制收集数量
if (ErrorCollector.errors.length > ErrorCollector.maxSize) {
ErrorCollector.errors.shift()
}
// 上报到远程服务器
ErrorCollector.reportToServer(errorInfo, stack)
}
private static reportToServer(error: string, stack?: string): void {
// 实际项目中实现错误上报
console.log(`上报错误: ${error}`)
}
static getRecentErrors(count: number = 10): Array<Object> {
return ErrorCollector.errors.slice(-count)
}
static clear(): void {
ErrorCollector.errors = []
}
}3.7.4 1.6.4 调试技巧与工具
// 1. 自定义调试工具
class DebugHelper {
// 性能计时
static measure<T>(label: string, fn: () => T): T {
let start: number = Date.now()
let result: T = fn()
let end: number = Date.now()
console.log(`[性能] ${label}: ${end - start}ms`)
return result
}
// 异步性能计时
static async measureAsync<T>(
label: string,
fn: () => Promise<T>
): Promise<T> {
let start: number = Date.now()
let result: T = await fn()
let end: number = Date.now()
console.log(`[性能] ${label}: ${end - start}ms`)
return result
}
// 数据快照
static snapshot(label: string, data: Object): void {
console.log(`[快照] ${label}:`)
console.log(JSON.stringify(data, null, 2))
}
// 条件断点(日志形式)
static assert(condition: boolean, message: string): void {
if (!condition) {
console.error(`[断言失败] ${message}`)
console.trace() // 打印调用栈
}
}
// 组件渲染追踪
static traceRender(componentName: string, props: Object): void {
console.log(`[渲染] ${componentName}:`, JSON.stringify(props))
}
}
// 2. 使用hilog进行日志管理
import { hilog } from '@kit.PerformanceAnalysisKit'
class AppLogger {
private static DOMAIN: number = 0x0001
private static TAG: string = "MyApp"
static debug(message: string, ...args: Object[]): void {
hilog.debug(AppLogger.DOMAIN, AppLogger.TAG, message, ...args.map(String))
}
static info(message: string, ...args: Object[]): void {
hilog.info(AppLogger.DOMAIN, AppLogger.TAG, message, ...args.map(String))
}
static warn(message: string, ...args: Object[]): void {
hilog.warn(AppLogger.DOMAIN, AppLogger.TAG, message, ...args.map(String))
}
static error(message: string, ...args: Object[]): void {
hilog.error(AppLogger.DOMAIN, AppLogger.TAG, message, ...args.map(String))
}
}
// 3. 组件调试技巧
@Component
struct DebuggableComponent {
@State renderCount: number = 0
@State debugInfo: string = ""
aboutToAppear(): void {
console.log(`[生命周期] DebuggableComponent aboutToAppear`)
}
aboutToReuse(params: Record<string, Object>): void {
console.log(`[生命周期] DebuggableComponent aboutToReuse`)
}
aboutToDisappear(): void {
console.log(`[生命周期] DebuggableComponent aboutToDisappear`)
}
build() {
// 记录渲染次数
this.renderCount++
DebugHelper.traceRender("DebuggableComponent", {
renderCount: this.renderCount
})
Column() {
Text(`渲染次数: ${this.renderCount}`)
.fontSize(16)
.fontColor(this.renderCount > 5 ? '#FF0000' : '#000000')
Text(this.debugInfo)
.fontSize(12)
.fontColor('#999999')
}
}
}3.8 本章小结
本章深入介绍了ArkTS高级语法与编程范式,主要内容包括:
ArkTS与TypeScript的关系:理解了ArkTS在TypeScript基础上的约束(禁用any、eval等)和扩展(声明式UI装饰器),掌握了更严格的静态类型检查机制。
高级类型系统:学习了联合类型、交叉类型、类型守卫、泛型约束、条件类型等高级类型特性,能够编写类型安全且高度复用的代码。
异步编程:掌握了Promise链式调用、async/await高级模式、并发控制(all/race/allSettled)以及TaskPool和Worker多线程方案。
函数式编程:理解了高阶函数、闭包、柯里化、偏函数和不可变数据模式,能够运用函数式思维解决实际问题。
模块系统:掌握了ES Module规范、循环依赖处理、动态导入和包管理最佳实践。
错误处理与调试:学习了结构化错误处理、自定义异常类层次、全局异常捕获和调试工具的使用。
3.9 练习题
3.9.1 一、单选题
1. 在ArkTS中,以下哪个特性是被禁止使用的?
A. 泛型 B. async/await C. any类型 D. 联合类型
答案:C
解析: ArkTS禁止使用any类型,这是与TypeScript的重要区别之一。ArkTS要求所有变量必须有明确的类型声明,不允许使用any作为”逃逸舱口”。泛型、async/await和联合类型在ArkTS中都是支持的。
2. 以下关于TaskPool和Worker的说法,正确的是?
A. TaskPool适合长期运行的后台任务 B. Worker适合短期计算密集型任务 C. TaskPool中的任务函数需要使用@Concurrent装饰器 D. Worker不能与主线程通信
答案:C
解析: TaskPool中的任务函数必须使用@Concurrent装饰器标记。TaskPool更适合短期、可并行化的计算任务;Worker更适合长期运行、需要维护状态的后台任务。Worker可以通过postMessage与主线程通信。
3. 在泛型约束 T extends HasLength 中,extends 关键字的含义是?
A. T继承HasLength B. T必须是HasLength的子类 C. T必须包含HasLength定义的所有属性 D. T就是HasLength类型
答案:C
解析: 在泛型约束中,extends 表示类型T必须满足HasLength接口所定义的约束,即T必须包含length属性。这不是传统意义上的继承,而是结构类型的约束。
3.9.2 二、多选题
4. 以下哪些是ArkTS中合法的异步编程模式?
A. Promise链式调用 B. async/await C. 回调函数 D. TaskPool并发
答案:A、B、C、D
解析: ArkTS支持所有标准的异步编程模式,包括Promise链式调用、async/await语法、传统的回调函数,以及HarmonyOS特有的TaskPool并发方案。开发者可以根据场景选择合适的异步模式。
5. 以下关于闭包的描述,正确的有哪些?
A. 闭包可以访问外部函数的局部变量 B. 闭包会导致被捕获的变量在外部函数返回后仍然存活 C. 闭包可能造成内存泄漏,需要谨慎使用 D. ArkTS禁止使用闭包
答案:A、B、C
解析: 闭包是函数式编程的核心概念。闭包可以捕获并记住其外部函数的作用域,即使外部函数已经返回。这既是闭包的强大之处,也可能导致内存问题,需要合理使用。ArkTS完全支持闭包。
3.9.3 三、判断题
6. ArkTS中的@Observed装饰器可以使类的属性变化被UI框架感知。
答案:正确
解析: @Observed装饰器标记的类,其属性变化会被ArkUI框架自动追踪,当属性值改变时,使用该属性的组件会自动重新渲染。这是HarmonyOS状态管理的基础机制之一。
7. Promise.allSettled()在任意一个Promise被reject时会立即返回。
答案:错误
解析: Promise.allSettled()会等待所有Promise都完成(无论fulfilled还是rejected),然后返回每个Promise的状态和结果。只有Promise.all()才会在任意一个Promise被reject时立即返回。Promise.race()则是返回最先完成的结果。
8. 在ArkTS中,可以使用as关键字进行任意类型之间的断言转换。
答案:错误
解析: ArkTS对类型断言有严格限制,不允许在完全不相关的类型之间进行断言转换。与TypeScript不同,ArkTS更倾向于使用类型守卫(typeof、instanceof等)来进行安全的类型收窄,而不是使用as断言。