谁能告知一下ArkTS相关知识点总结,

ArkTS相关知识点总结

HarmonyOS
2024-06-11 20:29:27
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
savan

一、ArkTS和TS差异

TS是JS的超集:即TS完全兼容JS的语法,JS不一定兼容TS的语法。


TS

ArkTS

类型检查

可配置:TS的类型检查可以自由配置为严格或者宽松。

不可配置:ArkTS的类型检查只能为严格,也有是变量必须有类型。

编译

编译为JavaScript

编译后擦除类型信息

编译为字节码

编译后保留类型信息

执行

可以在任意能运行JavaScript的引擎上运行

引擎运行时执行运行时类型检查

在ArkRuntime上运行

引擎运行时仅执行少量的类型检查


二、ArkTs比TS增加

1.ArkUI范式

(1)装饰器:用来装饰类、结构体、方法以及变量,赋予其特殊的含义,如 @Entry、@Component、@State都是装饰器。具体而言,@Component表示这是个自定义组件;@Entry则表示是入口组件;@State表示组件中的状态变量,这个状态变化会引起相应的UI的自动刷新,管理组件状态具体有三种:组件内@State,从父组件单向同步状态的@Prop以及父子组件双向同步状态和监听的@Link、@Watch。

(2)自定义组件:可复用的UI单元,可组合其它组件被 @Component装饰的。

(3)内置组件:框架中默认内置的基础和布局组件,可直接被开发者调用,如Column、Text、Divider、Button。

(4)事件方法:用于添加组件对事件的响应逻辑,统一通过事件方法进行设置,如跟随在Button后面的onClick()。

(5)属性方法:用于组件属性的配置,统一通过属性方法进行设置,如fontSize()、width()、height()、color()等,可通过链式调用的方式设置多项属性。

三、语言规范

1. 声明

变量

使用let进行变量的声明,例如:

let hi: string = 'hello'

常量

使用关键期const开头进行声明,该常量只能被赋值一次,例如:

Const hello: string= 'hello'

2. 类型

类型

示例

说明

Number/Number

let n1 = 3.14let n2 = 0o777

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

Boolean/boolean

let isDone: Boolean = false

由true和false两个逻辑值组成。

String

let s1 = ‘hello’

代表字符序列,由单引号(')或双引号(')之间括起来的零个或多个字符组成;可以使用转义字符来表示字符。

Void


用于指定函数没有返回值。此类型只有一个值,同样是void。

Object


Object类型是所有引用类型的基类型。任何值,包括基本类型的值(它们会被自动装箱),都可以直接被赋给Object类型的变量。

Array

let names: string[] = ['Alice', 'Bob', 'Carol']

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

Enum

enum Color { Red, Green, Blue }

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

Union

type Animal = Cat | Dog | Frog | numberlet animal: Animal = new Cat()

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

tuple

let x: [string, number]

元祖类型,即数组中支持多种数据类型的元素。


3. 语句

语句包含if,switch,for,for-of,?,While,Do-While,Break,Continue,Throw和Try。

大部分语句写法基本类似Java,使用K & R风格,其中新增了一个For-of替代了Java for遍历语法糖。

使用for-of语句可遍历数组或字符串。示例如下:

for (variable of iterable)  
 statement

4. 函数

函数声明

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

以下示例是一个简单的函数,包含两个string类型的参数,返回类型为string:

function add(x: string, y: string): string { 
  let z: string = `${x} ${y}` 
  return z 
}

可选参数

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

function hello(name?: string) { 
  if (name == undefined) { 
    console.log('Hello!') 
  } else { 
    console.log('Hello, ${name}!') 
  } 
}

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

function multiply(n: number, coeff: number = 2): number { 
  return n * coeff 
} 
multiply(2)  // 返回2*2 
multiply(2, 3) // 返回2*3

Rest参数

函数的最后一个参数可以是rest参数。使用rest参数时,允许函数或方法接受任意数量的实参。

function sum(...numbers: number[]): number { 
  let res = 0 
  for (let n of numbers) 
    res += n 
  return res 
} 
sum() // 返回0 
sum(1, 2, 3) // 返回6

返回类型

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

// 显式指定返回类型 
function foo(): string { return 'foo' } 
// 推断返回类型为string 
function goo() { return 'goo' }

函数作用域

局部变量仅作用于函数自身,如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。,与Swift/C++/C一致。

函数类型

函数类型通常用于定义回调:

type trigFunc = (x: number) => number // 这是一个函数类型 
function do_action(f: trigFunc) { 
   f(3.141592653589) // 调用函数 
} 
do_action(Math.sin) // 将函数作为参数传入

Lambda函数

函数可以定义为箭头函数,使用方式类似java的lambda表达式,例如:

let sum = (x: number, y: number): number => { 
  return x + y 
}

箭头函数的返回类型可以省略;省略时,返回类型通过函数体推断。

表达式可以指定为箭头函数,使表达更简短,因此以下两种表达方式是等价的:

let sum1 = (x: number, y: number) => { return x + y } 
let sum2 = (x: number, y: number) => x + y

该函数可以获取外界的变量,如:

function f(): () => number { 
  let count = 0 
  return (): number => { count++; return count } 
} 
let z = f() 
console.log(z()) // 输出:1 
console.log(z()) // 输出:2

5. 类

ArkTS与swift语法习惯类似,其类的成员包含以下部分:

字段

(1)实例字段(类变量)

class Person { 
  name: string = '' 
  age: number = 0 
  constructor(n: string, a: number) { 
    this.name = n 
    this.age = a 
  } 
  GetName(): string { 
    return this.name 
  } 
} 
let p1 = new Person('Alice', 25) 
console.log(p1.name) 
let p2 = new Person('Bob', 28) 
console.log(p2.GetName())

(2)静态字段(静态变量)

class Person { 
  static numberOfPersons = 0 
  constructor() { 
     // ... 
     Person.numberOfPersons++ 
     // ... 
  } 
} 
console.log(Person.numberOfPersons)

(3)初始化

变量最好在声明时直接进行初始化,如果值不初始化,则需要针对其值为undefined的情况进行处理。

class Person { 
  name ?: string // 可能为`undefined` 
  
  setName(n:string): void { 
    this.name = n 
  } 
  // 编译时错误:name可以是"undefined",所以将这个API的返回值类型标记为string 
  getNameWrong(): string { 
    return this.name 
  } 
  getName(): string | undefined { // 返回类型匹配name的类型 
    return this.name 
  } 
} 
let jack = new Person() 
// 假设代码中没有对name赋值,例如调用"jack.setName('Jack')" 
  
// 编译时错误:编译器认为下一行代码有可能会访问undefined的属性,报错 
console.log(jack.getName().length);  // 编译失败 
console.log(jack.getName()?.length); // 编译成功,没有运行时错误

方法

同样的,方法也分为实例方法(通过对象访问)和静态方法(通过类或对象访问)。

静态方法使用static进行标注,例如:

class Cl { 
  static staticMethod(): string { 
    return 'this is a static method.' 
  } 
} 
console.log(Cl.staticMethod())

在ArkTS中,也可以对方法进行继承/重写。

构造函数

构造函数使用方式与其他面向对象语言类似(swift),可以无参构造/使用super调用父类构造器/构造器重载。

调用父类构造器:

class Rectangle { 
  constructor(width: number, height: number) { 
    // ... 
  } 
} 
class Square extends Rectangle { 
  constructor(side: number) { 
    super(side, side) 
  } 
}

构造器重载:

class C { 
  constructor()             /* 第一个签名 */ 
  constructor(x: string)    /* 第二个签名 */ 
  constructor(x?: string) { /* 实现签名 */ 
    console.log(x) 
  } 
} 
let c1 = new C()      // OK,使用第一个签名 
let c2 = new C('abc') // OK,使用第二个签名

可见性修饰符

可见性修饰符包含 public,private,protected和default(默认声明,不用添加)。

对象字面量

对象字面量是一个表达式,可用于创建类实例并提供一些初始值。它在某些情况下更方便,可以用来代替new表达式。对象字面量的表示方式是:封闭在花括号对({})中的'属性名:值'的列表(即用来替代声明对象,类似new object())。

class C { 
  n: number = 0 
  s: string = '' 
} 
let c: C = {n: 42, s: 'foo'}

泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。常用对象字面量来初始化该类型的值。例如对于map类型,赋值可以表示为:

let map: Record<string, number> = { 
  'John': 25, 
  'Mary': 21, 
} 
console.log(map['John']) // prints 25

四、并发

1. 异步并发

Promise

Promise是一种用于处理异步操作的对象,可以将异步操作转换为类似于同步操作的风格,以方便代码编写和维护。Promise提供了一个状态机制来管理异步操作的不同阶段,并提供了一些方法来注册回调函数以处理异步操作的成功或失败的结果。

Promise有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)。Promise对象创建后处于pending状态,并在异步操作完成后转换为fulfilled或rejected状态。

最基本的用法是通过构造函数实例化一个Promise对象,同时传入一个带有两个参数的函数,通常称为executor函数。executor函数接收两个参数:resolve和reject,分别表示异步操作成功和失败时的回调函数,例如:

const promise: Promise<number> = new Promise((resolve: Function, reject: Function) => { 
setTimeout(() => { 
  const randomNumber: number = Math.random(); 
  if (randomNumber > 0.5) { 
    resolve(randomNumber); 
  } else { 
    reject(new Error('Random number is too small')); 
  } 
}, 1000); 
})

Promise对象创建后,可以使用then方法和catch方法指定fulfilled状态和rejected状态的回调函数。then方法可接受两个参数,一个处理fulfilled状态的函数,另一个处理rejected状态的函数。只传一个参数则表示状态改变就执行,不区分状态结果。使用catch方法注册一个回调函数,用于处理“失败”的结果,即捕获Promise的状态改变为rejected状态或操作失败抛出的异常。例如:

import { BusinessError } from '@ohos.base'; 
  
promise.then((result: number) => { 
 console.info(`Random number is ${result}`); 
}).catch((error: BusinessError) => { 
 console.error(error.message); 
});

上述代码中,then方法的回调函数接收Promise对象的成功结果作为参数,并将其输出到控制台上。如果Promise对象进入rejected状态,则catch方法的回调函数接收错误对象作为参数,并将其输出到控制台上。

Async/await

async/await是一种用于处理异步操作的Promise语法糖,使得编写异步代码变得更加简单和易读。通过使用async关键字声明一个函数为异步函数,并使用await关键字等待Promise的解析(完成或拒绝),以同步的方式编写异步操作的代码。

async函数是一个返回Promise对象的函数,用于表示一个异步操作。在async函数内部,可以使用await关键字等待一个Promise对象的解析,并返回其解析值。如果一个async函数抛出异常,那么该函数返回的Promise对象将被拒绝,并且异常信息会被传递给Promise对象的onRejected()方法,此时,可以使用try/catch块来捕获异步操作中的异常,例如:

async function myAsyncFunction(): Promise<void> { 
  try { 
    const result: string = await new Promise((resolve: Function) => { 
      resolve('Hello, world!'); 
    }); 
  } catch (e) { 
    console.error(`Get exception: ${e}`); 
  } 
} 
myAsyncFunction();

2. 同步并发

对比

TaskPool(任务池)和Worker的作用是为应用程序提供一个多线程的运行环境,用于处理耗时的计算任务或其他密集型任务。可以有效地避免这些任务阻塞主线程,从而最大化系统的利用率,降低整体资源消耗,并提高系统的整体性能。

实现

TaskPool

Worker

内存模型

线程间隔离,内存不共享。

线程间隔离,内存不共享。

参数传递机制

支持ArrayBuffer转移和SharedArrayBuffer共享。

支持ArrayBuffer转移和SharedArrayBuffer共享。

参数传递

直接传递,无需封装,默认进行transfer。

消息对象唯一参数,需要自己封装。

方法调用

直接将方法传入调用。

在Worker线程中进行消息解析并调用对应方法。

返回值

异步调用后默认返回。

主动发送消息,需在onmessage解析赋值。

生命周期

TaskPool自行管理生命周期,无需关心任务负载高低。

开发者自行管理Worker的数量及生命周期。

任务池个数上限

自动管理,无需配置。

最多开启8个Worker。

任务执行时长上限

3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时)。

无限制。

设置任务的优先级

支持配置任务优先级。

不支持。

执行任务的取消

支持取消已经发起的任务。

不支持。


应用场景

TaskPool偏向独立任务(线程级)维度,超长任务(大于3分钟)会被系统自动回收;而Worker偏向线程的维度,支持长时间占据线程执行。

常见的一些开发场景及适用具体说明如下:

(1)运行时间超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时)的任务。例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker。

(2)有关联的一系列同步任务。例如某数据库操作时,要用创建的句柄操作,包含增、删、改、查多个任务,要保证同一个句柄,需要使用Worker。

(3)需要设置优先级的任务。例如图库直方图绘制场景,后台计算的直方图数据会用于前台界面的显示,影响用户体验,需要高优先级处理,需要使用TaskPool。

(4)需要频繁取消的任务。例如图库大图浏览场景,为提升体验,会同时缓存当前图片左右侧各2张图片,往一侧滑动跳到下一张图片时,要取消另一侧的一个缓存任务,需要使用TaskPool。

(5)大量或者调度点较分散的任务。例如大型应用的多个模块包含多个耗时任务,不方便使用8个Worker去做负载管理,推荐采用TaskPool。

TaskPool

实现任务的函数需要使用装饰器@Concurrent标注,且仅支持在.ets文件中使用。

(1)导入模块

import taskpool from '@ohos.taskpool';

(2)执行函数

@Concurrent 
function printArgs(args: number): number { 
    console.log("printArgs: " + args); 
    return args; 
} 
taskpool.execute(printArgs, 100).then((value: number) => { // 100: test number 
  console.log("taskpool result: " + value); 
});

Worker

Worker最多同时运行八个。

(1)导入模块

// 导入模块 
import worker form '@ohos.worker';

(2)执行命令

// 写法一 
// Stage模型-目录同级(entry模块下,workers目录与pages目录同级) 
const worker1: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts', {name:"first worker in Stage model"}); 
// Stage模型-目录不同级(entry模块下,workers目录是pages目录的子目录) 
const worker2: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/pages/workers/MyWorker.ts'); 
// 写法二 
// Stage模型-目录同级(entry模块下,workers目录与pages目录同级),假设bundlename是com.example.workerdemo 
const worker3: worker.ThreadWorker = new worker.ThreadWorker('@bundle:com.example.workerdemo/entry/ets/workers/worker'); 
// Stage模型-目录不同级(entry模块下,workers目录是pages目录的子目录),假设bundlename是com.example.workerdemo 
const worker4: worker.ThreadWorker = new worker.ThreadWorker('@bundle:com.example.workerdemo/entry/ets/pages/workers/worker');
分享
微博
QQ
微信
回复
2024-06-12 17:11:23
相关问题
帐号授权相关问题,和大家讨论一下
11464浏览 • 3回复 待解决
想了解一下SM4相关案例
318浏览 • 1回复 待解决
一下 ArkTS中math库是哪个?
1483浏览 • 2回复 待解决
告知静态订阅相关方法
335浏览 • 1回复 待解决
ob有如何报错,麻烦帮忙看一下
3382浏览 • 1回复 待解决
请教一下关于Ticktimer 的疑问?
2069浏览 • 1回复 待解决
编译OpenHarmony2.0失败,求助一下
7557浏览 • 3回复 已解决
请问一下tab按钮组切换效果
429浏览 • 1回复 待解决
请教一下如何开关闪光灯
178浏览 • 1回复 待解决
请教一下关于应用分栏实现
260浏览 • 1回复 待解决
请教一下如何实现函数的重载
260浏览 • 1回复 待解决
想了解一下MD5算法示例。
327浏览 • 1回复 待解决
谁分享一下如何实现匿名内部类
323浏览 • 1回复 待解决
能否审核一下传上去的文档
1583浏览 • 5回复 待解决
前辈们能讲一下如何看polardb代码吗?
1244浏览 • 1回复 待解决
分享一下你的鸿蒙系统使用感受吧
2836浏览 • 1回复 待解决
请问一下鸿蒙的pad应用该如何签名?
6750浏览 • 1回复 待解决