基本

构造函数

属性get set,protected子类才能访问

继承(extends,C#用:,super调用父类,C#用base)

ArkTS中重写父类方法,父类不需要像C#那种定义虚方法或抽象方法

接口

基本

接口可以继承接口,接口中定义的没函数时候可以直接字面量的方式使用接口

接口中可以定义getter,setter,默认的color: string;是他的简写

interface Style {
  get color(): string;
  set color(x: string);
}

interface Style {
  color: string;
}

class StyledRectangle implements Style {
  private _color: string = '';
  get color(): string { return this._color; }
  set color(x: string) { this._color = x; }
}

字面量使用

很容易推导类型,去掉了new关键字,直接初始化

class C {
  n: number = 0;
  s: string = '';
}

function foo(c: C) {}

let c: C

c = {n: 42, s: 'foo'};  // 使用变量的类型
foo({n: 42, s: 'foo'}); // 使用参数的类型

function bar(): C {
  return {n: 42, s: 'foo'}; // 使用返回类型
}

也可以数组中使用

class C {
  n: number = 0;
  s: string = '';
}
let cc: C[] = [{n: 1, s: 'a'}, {n: 2, s: 'b'}];

实现 implements

命名空间,使用export导出

模块导入与导出

代码拆分多个ets文件

比如定义个Person类Person.ets文件,其他文件想使用,可以使用export导出,可以导出类,变量和函数

使用的地方导入,与导入使用as关键字别名

export from,提取1个ets文件中的export导出

Index.ets导出了Util.ets的导出,然后Page.ets直接导入Index.ets,就可以间接使用Util.ets了

动态import

支持条件延迟加载1个模块,如果一开始就定义在顶部的import,就会立即被导入。

其他示例

// Calc.ts
export function add(a:number, b:number):number {
  let c = a + b;
  console.info('Dynamic import, %d + %d = %d', a, b, c);
  return c;
}

// Index.ts
import("./Calc").then((obj: ESObject) => {
  console.info(obj.add(3, 5));  
}).catch((err: Error) => {
  console.error("Module dynamic import error: ", err);
});

如果在异步函数中,可以使用let module = await import(modulePath)。

// say.ts
export function hi() {
  console.log('Hello');
}
export function bye() {
  console.log('Bye');
}

async function test() {
  let ns = await import('./say');
  let hi = ns.hi;
  let bye = ns.bye;
  hi();
  bye();
}

动态加载-ArkTS模块化-ArkTS运行时-ArkTS(方舟编程语言)-应用框架 - 华为HarmonyOS开发者

导入内置的

import UIAbility from '@ohos.app.ability.UIAbility';

import { UIAbility } from '@kit.AbilityKit';

import { UIAbility, Ability, Context } from '@kit.AbilityKit';

import * as module from '@kit.AbilityKit';(可能会导入过多无需使用的模块,导致编译后的HAP包太大,占用过多资源,请谨慎使用)

补充 

关键字this只能在类的实例方法中使用。

let和const的的变量区别:const开头的声明引入只读常量,该常量只能被赋值一次,let后面可以修改

string字符串反向单引号,可以使用${变量}

let a = 'Success';
let s3 = `The result is ${a}`;

void是引用类型,因此它可以用于泛型类型参数

联合类型的判断 instanceof  类似C#的typeof或者is关键字

class Cat { sleep () {}; meow () {} }
class Dog { sleep () {}; bark () {} }
class Frog { sleep () {}; leap () {} }

type Animal = Cat | Dog | Frog;

function foo(animal: Animal) {
  if (animal instanceof Frog) {
    animal.leap();  // animal在这里是Frog类型
  }
  animal.sleep(); // Animal具有sleep方法
}

运算符基本一致,+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=

比较运算符列举2个C#没的

try catch (基本和C#一致)

throw Error('this error')

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

自定义异常,继承Error

class ZeroDivisor extends Error {}

function divide (a: number, b: number): number{
  if (b == 0) throw new ZeroDivisor();
  return a / b;
}

function process (a: number, b: number) {
  try {
    let res = divide(a, b);
    console.log('result: ' + res);
  } catch (x) {
    console.log('some error');
  }
}

function processData(s: string) {
  let error: Error | null = null;

  try {
    console.log('Data processed: ' + s);
    // ...
    // 可能发生异常的语句
    // ...
  } catch (e) {
    error = e as Error;
    // ...
    // 异常处理
    // ...
  } finally {
    if (error != null) {
      console.log(`Error caught: input='${s}', message='${error.message}'`);
    }
  }
}

函数重载

function foo(x: number): void;            /* 第一个函数定义 */
function foo(x: string): void;            /* 第二个函数定义 */
function foo(x: number | string): void {  /* 函数实现 */
}

foo(123);     //  OK,使用第一个定义
foo('aa'); // OK,使用第二个定义

构造函数重载

class C {
  constructor(x: number)             /* 第一个签名 */
  constructor(x: string)             /* 第二个签名 */
  constructor(x: number | string) {  /* 实现签名 */
  }
}
let c1 = new C(123);      // OK,使用第一个签名
let c2 = new C('abc');    // OK,使用第二个签名

也支持static,用法和C#一致

 static numberOfPersons = 0;

  static staticMethod(): string {
    return 'this is a static method.';
  }

可空string

默认情况下,ArkTS中的所有类型都是不可为空的

其他语言可能 string? AAA,在ArkTS中用 AAA?:string 表示可能为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的属性,报错
jack.getName().length;  // 编译失败

jack.getName()?.length; // 编译成功,没有运行时错误

Record类型的对象字面量

泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。常用对象字面量来初始化该类型的值,类型K可以是字符串类型或数值类型,而V可以是任何类型。类似C#的Dictionary<key,value>知识点

interface PersonInfo {
  age: number;
  salary: number;
}
let map: Record<string, PersonInfo> = {
  'John': { age: 25, salary: 10},
  'Mary': { age: 21, salary: 20}
}
使用 map['John']

抽象类(和C#一致)

不能被直接new,可以被抽象类继承,抽象方法只能在抽象类中

abstract class Base {
  field: number;
  constructor(p: number) { 
    this.field = p; 
  }
  abstract method(p: string);
}

class Derived extends Base {
  constructor(p: number) {
    super(p); 
  }
method(p: string) {}
}

抽象类里面可以有方法的实现,但是接口完全都是抽象的,不存在方法的实现;

泛型类型和函数

和C#一致,C#用where约束泛型,ArkTS直接变量名后面加条件

interface Hashable {
  hash(): number;
}
class MyHashMap<Key extends Hashable, Value> {
  public set(k: Key, v: Value) {
    let h = k.hash();
    // ...其他代码...
  }
}

使用泛型可以编写更通用的代码,这里只能number类型的数组,这里是返回任意数组的最后1个元素。

function last(x: number[]): number {
  return x[x.length - 1];
}
last([1, 2, 3]); // 3

修改泛型写法如下

function last<T>(x: T[]): T {
  return x[x.length - 1];
}
// 显式设置的类型实参
last<string>(['aa', 'bb']);
last<number>([1, 2, 3]);

// 隐式设置的类型实参
// 编译器根据调用参数的类型来确定类型实参
last([1, 2, 3]);

泛型可以指定默认类型

class SomeType {}
interface Interface <T1 = SomeType> { }
class Base <T2 = SomeType> { }
class Derived1 extends Base implements Interface { }
// Derived1在语义上等价于Derived2
class Derived2 extends Base<SomeType> implements Interface<SomeType> { }

function foo<T = number>(): T {
  // ...
}
foo();
// 此函数在语义上等价于下面的调用
foo<number>();

非空断言运算符

class A {
  value: number = 0;
}

function foo(a: A | null) {
  a.value;   // 编译时错误:无法访问可空值的属性
  a!.value;  // 编译通过,如果运行时a的值非空,可以访问到a的属性;如果运行时a的值为空,则发生运行时异常
}

a ?? b等价于三元运算符(a != null && a != undefined) ? a : b。

可选链

返回值后面用 | 跟很多可能返回的值

class Person {
  nick: string | null = null;
  spouse?: Person

  setSpouse(spouse: Person): void {
    this.spouse = spouse;
  }

  getSpouseNick(): string | null | undefined {
    return this.spouse?.nick;
  }

  constructor(nick: string) {
    this.nick = nick;
    this.spouse = undefined;
  }
}

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐