華為開發(fā)之ArkTS筆記1 2024-07-02 周二

來源

ArkTS來自TypeScript,TS就是TypeScript的縮寫。而TypeScript就是來自JavaScript,所以所謂的兩種語言其實(shí)就是一種語言JavaScript。當(dāng)然,還是按照官方的建議,使用ArkTS就可以了,反正都是JS生態(tài)。

語言簡介

  • let是變量,const是常量,定義時(shí)帶上初始值,可以推斷類型
let hi1: string = 'hello';
let hi2 = 'hello, world';
const hi3 = 'hello, world! can not change';
  • 數(shù)字的類型是number,不用區(qū)分整數(shù)和浮點(diǎn)數(shù);默認(rèn)是10進(jìn)制;16進(jìn)制用0x開頭;

  • boolean類型由true和false兩個(gè)邏輯值組成。

  • 字符串字面量由單引號(hào)(')或雙引號(hào)(")之間括起來的零個(gè)或多個(gè)字符組成(實(shí)際使用優(yōu)先用雙引號(hào))。字符串字面量還有一特殊形式,是用反向單引號(hào)(`)括起來的模板字面量。字符串插值用${}

let s1 = 'Hello, world!\n';
let s2 = 'this is a string';
let a = 'Success';
let s3 = `The result is ${a}`;
  • Object類型是所有引用類型的基類型。任何值,包括基本類型的值(它們會(huì)被自動(dòng)裝箱),都可以直接被賦給Object類型的變量。

  • 數(shù)組Array類型

let names: string[] = ['Alice', 'Bob', 'Carol'];
  • enum類型,又稱枚舉類型,是預(yù)先定義的一組命名值的值類型,其中命名值又稱為枚舉常量。
enum ColorSet { Red, Green, Blue }
let c: ColorSet = ColorSet.Red;
  • union類型,即聯(lián)合類型,是由多個(gè)類型組合成的引用類型。聯(lián)合類型包含了變量可能的所有類型。(這個(gè)有點(diǎn)特殊,合適的地方用起來)
class Cat { sleep () {}; meow () {} }
class Dog { sleep () {}; bark () {} }
class Frog { sleep () {}; leap () {} }

type Animal = Cat | Dog | Frog | number

let animal: Animal = new Frog();
if (animal instanceof Frog) {
  let frog: Frog = animal as Frog; // animal在這里是Frog類型
  animal.leap();
  frog.leap();
  // 結(jié)果:青蛙跳了兩次
}

animal.sleep (); // 任何動(dòng)物都可以睡覺
  • Aliases類型為匿名類型(數(shù)組、函數(shù)、對(duì)象字面量或聯(lián)合類型)提供名稱,或?yàn)橐延蓄愋吞峁┨娲Q。
type Matrix = number[][];
type Handler = (s: string, no: number) => string;
type Predicate <T> = (x: T) => Boolean;
type NullableObject = Object | null;
  • if 要帶括號(hào),條件可以是任何表達(dá)式,會(huì)隱式轉(zhuǎn)換為boolean類型(這點(diǎn)不如Swift)

  • switch語句的break不應(yīng)該省略;如果沒有break語句,則執(zhí)行switch中的下一個(gè)label對(duì)應(yīng)的代碼塊。(這點(diǎn)不如Swift)

  • 使用for-of語句可遍歷數(shù)組或字符串。

for (let ch of 'a string object') {
  /* process ch */
}
  • 錯(cuò)誤處理:try catch finally結(jié)構(gòu)
function processData(s: string) {
  let error: Error | null = null;  

  try {
    console.log('Data processed: ' + s);
    // ...
    // 可能發(fā)生異常的語句
    // ...
  } catch (e) {
    error = e as Error;
    // ...
    // 異常處理
    // ...
  } finally {
    if (error != null) {
      console.log(`Error caught: input='${s}', message='${error.message}'`);
    }
  }
}
  • 函數(shù)可選參數(shù)的格式可為name?: Type
function hello(name?: string) {
  if (name == undefined) {
    console.log('Hello!');
  } else {
    console.log(`Hello, ${name}!`);
  }
}
  • 可選參數(shù)的另一種形式為設(shè)置的參數(shù)默認(rèn)值。如果在函數(shù)調(diào)用中這個(gè)參數(shù)被省略了,則會(huì)使用此參數(shù)的默認(rèn)值作為實(shí)參。
function multiply(n: number, coeff: number = 2): number {
  return n * coeff;
}
multiply(2);  // 返回2*2
multiply(2, 3); // 返回2*3
  • 函數(shù)的最后一個(gè)參數(shù)可以是rest參數(shù)。使用rest參數(shù)時(shí),允許函數(shù)或方法接受任意數(shù)量的實(shí)參。
function sum(...numbers: number[]): number {
  let res = 0;
  for (let n of numbers)
    res += n;
  return res;
}

sum() // 返回0
sum(1, 2, 3) // 返回6
  • 如果可以從函數(shù)體內(nèi)推斷出函數(shù)返回類型,則可在函數(shù)聲明中省略標(biāo)注返回類型。
// 顯式指定返回類型
function foo(): string { return 'foo'; }

// 推斷返回類型為string
function goo() { return 'goo'; }
  • 不需要返回值的函數(shù)的返回類型可以顯式指定為void或省略標(biāo)注。這類函數(shù)不需要返回語句。
function hi1() { console.log('hi'); }
function hi2(): void { console.log('hi'); }
  • 閉包是由函數(shù)及聲明該函數(shù)的環(huán)境組合而成的。該環(huán)境包含了這個(gè)閉包創(chuàng)建時(shí)作用域內(nèi)的任何局部變量。
    在下例中,z是執(zhí)行f時(shí)創(chuàng)建的g箭頭函數(shù)實(shí)例的引用。g的實(shí)例維持了對(duì)它的環(huán)境的引用(變量count存在其中)。因此,當(dāng)z被調(diào)用時(shí),變量count仍可用。
function f(): () => number {
  let count = 0;
  let g = (): number => { count++; return count; };
  return g;
}

let z = f();
z(); // 返回:1
z(); // 返回:2
  • 我們可以通過編寫重載,指定函數(shù)的不同調(diào)用方式。具體方法為,為同一個(gè)函數(shù)寫入多個(gè)同名但簽名不同的函數(shù)頭,函數(shù)實(shí)現(xiàn)緊隨其后。
function foo(x: number): void;            /* 第一個(gè)函數(shù)定義 */
function foo(x: string): void;            /* 第二個(gè)函數(shù)定義 */
function foo(x: number | string): void {  /* 函數(shù)實(shí)現(xiàn) */
}

foo(123);     //  OK,使用第一個(gè)定義
foo('aa'); // OK,使用第二個(gè)定義
  • 為了減少運(yùn)行時(shí)的錯(cuò)誤和獲得更好的執(zhí)行性能,ArkTS要求所有字段在聲明時(shí)或者構(gòu)造函數(shù)中顯式初始化。如果可能為空,要加?
class Person {
  name?: string // 可能為`undefined`

  setName(n:string): void {
    this.name = n;
  }

  // 編譯時(shí)錯(cuò)誤:name可以是"undefined",所以將這個(gè)API的返回值類型標(biāo)記為string
  getNameWrong(): string {
    return this.name;
  }

  getName(): string | undefined { // 返回類型匹配name的類型
    return this.name;
  }
}

let jack = new Person();
// 假設(shè)代碼中沒有對(duì)name賦值,例如調(diào)用"jack.setName('Jack')"

// 編譯時(shí)錯(cuò)誤:編譯器認(rèn)為下一行代碼有可能會(huì)訪問undefined的屬性,報(bào)錯(cuò)
jack.getName().length;  // 編譯失敗

jack.getName()?.length; // 編譯成功,沒有運(yùn)行時(shí)錯(cuò)誤
  • setter和getter可用于提供對(duì)對(duì)象屬性的受控訪問。
class Person {
  name: string = ''
  private _age: number = 0
  get age(): number { return this._age; }
  set age(x: number) {
    if (x < 0) {
      throw Error('Invalid age argument');
    }
    this._age = x;
  }
}

let p = new Person();
p.age; // 輸出0
p.age = -42; // 設(shè)置無效age值會(huì)拋出錯(cuò)誤
  • 關(guān)鍵字super可用于訪問父類的實(shí)例字段、實(shí)例方法和構(gòu)造函數(shù)。在實(shí)現(xiàn)子類功能時(shí),可以通過該關(guān)鍵字從父類中獲取所需接口
class RectangleSize {
  protected height: number = 0
  protected width: number = 0

  constructor (h: number, w: number) {
    this.height = h;
    this.width = w;
  }

  draw() {
    /* 繪制邊界 */
  }
}
class FilledRectangle extends RectangleSize {
  color = ''
  constructor (h: number, w: number, c: string) {
    super(h, w); // 父類構(gòu)造函數(shù)的調(diào)用
    this.color = c;
  }

  draw() {
    super.draw(); // 父類方法的調(diào)用
    // super.height -可在此處使用
    /* 填充矩形 */
  }
}
  • 子類可以重寫其父類中定義的方法的實(shí)現(xiàn)。重寫的方法必須具有與原始方法相同的參數(shù)類型和相同或派生的返回類型。
class RectangleSize {
  // ...
  area(): number {
    // 實(shí)現(xiàn)
    return 0;
  }
}
class Square extends RectangleSize {
  private side: number = 0
  area(): number {
    return this.side * this.side;
  }
}
  • 通過重載簽名,指定方法的不同調(diào)用。具體方法為,為同一個(gè)方法寫入多個(gè)同名但簽名不同的方法頭,方法實(shí)現(xiàn)緊隨其后。
class C {
  foo(x: number): void;            /* 第一個(gè)簽名 */
  foo(x: string): void;            /* 第二個(gè)簽名 */
  foo(x: number | string): void {  /* 實(shí)現(xiàn)簽名 */
  }
}
let c = new C();
c.foo(123);     // OK,使用第一個(gè)簽名
c.foo('aa'); // OK,使用第二個(gè)簽名
  • 我們可以通過編寫重載簽名,指定構(gòu)造函數(shù)的不同調(diào)用方式。具體方法為,為同一個(gè)構(gòu)造函數(shù)寫入多個(gè)同名但簽名不同的構(gòu)造函數(shù)頭,構(gòu)造函數(shù)實(shí)現(xiàn)緊隨其后。
class C {
  constructor(x: number)             /* 第一個(gè)簽名 */
  constructor(x: string)             /* 第二個(gè)簽名 */
  constructor(x: number | string) {  /* 實(shí)現(xiàn)簽名 */
  }
}
let c1 = new C(123);      // OK,使用第一個(gè)簽名
let c2 = new C('abc');    // OK,使用第二個(gè)簽名
  • 對(duì)象字面量是一個(gè)表達(dá)式,可用于創(chuàng)建類實(shí)例并提供一些初始值。它在某些情況下更方便,可以用來代替new表達(dá)式。(JS對(duì)象的本質(zhì)是一個(gè)Map)
class C {
  n: number = 0
  s: string = ''
}

let c: C = {n: 42, s: 'foo'};
  • 泛型Record<K, V>用于將類型(鍵類型)的屬性映射到另一個(gè)類型(值類型)。常用對(duì)象字面量來初始化該類型的值:類型K可以是字符串類型或數(shù)值類型,而V可以是任何類型。
let map: Record<string, number> = {
  'John': 25,
  'Mary': 21,
}

map['John']; // 25
interface PersonInfo {
  age: number
  salary: number
}
let map: Record<string, PersonInfo> = {
  'John': { age: 25, salary: 10},
  'Mary': { age: 21, salary: 20}
}
  • 接口屬性可以是字段、getter、setter或getter和setter組合的形式。屬性字段只是getter/setter對(duì)的便捷寫法。以下表達(dá)方式是等價(jià)的:
interface Style {
  color: string
}

class StyledRectangle implements Style {
  color: string = ''
}
interface Style {
  get color(): string
  set color(x: string)
}

class StyledRectangle implements Style {
  private _color: string = ''
  get color(): string { return this._color; }
  set color(x: string) { this._color = x; }
}
  • 接口可以繼承其他接口
interface Style {
  color: string
}

interface ExtendedStyle extends Style {
  width: number
}
  • 泛型類型的類型參數(shù)可以綁定。例如,HashMap<Key, Value>容器中的Key類型參數(shù)必須具有哈希方法,即它應(yīng)該是可哈希的。
interface Hashable {
  hash(): number
}
class HasMap<Key extends Hashable, Value> {
  public set(k: Key, v: Value) {
    let h = k.hash();
    // ...其他代碼...
  }
}
  • 使用泛型函數(shù)可編寫更通用的代碼。比如返回?cái)?shù)組最后一個(gè)元素的函數(shù):
function last<T>(x: T[]): T {
  return x[x.length - 1];
}

// 顯式設(shè)置的類型實(shí)參
last<string>(['aa', 'bb']);
last<number>([1, 2, 3]);

// 隱式設(shè)置的類型實(shí)參
// 編譯器根據(jù)調(diào)用參數(shù)的類型來確定類型實(shí)參
last([1, 2, 3]);
  • 泛型類型的類型參數(shù)可以設(shè)置默認(rèn)值。這樣可以不指定實(shí)際的類型實(shí)參,而只使用泛型類型名稱。下面的示例展示了類和函數(shù)的這一點(diǎn)。
class SomeType {}
interface Interface <T1 = SomeType> { }
class Base <T2 = SomeType> { }
class Derived1 extends Base implements Interface { }
// Derived1在語義上等價(jià)于Derived2
class Derived2 extends Base<SomeType> implements Interface<SomeType> { }

function foo<T = number>(): T {
  // ...
}
foo();
// 此函數(shù)在語義上等價(jià)于下面的調(diào)用
foo<number>();
  • 可以為空值的變量定義為聯(lián)合類型T | null。
let x: number | null = null;
x = 1;    // ok
x = null; // ok
if (x != null) { /* do something */ }
  • 空值合并二元運(yùn)算符??用于檢查左側(cè)表達(dá)式的求值是否等于null或者undefined。如果是,則表達(dá)式的結(jié)果為右側(cè)表達(dá)式;否則,結(jié)果為左側(cè)表達(dá)式。換句話說,a ?? b等價(jià)于三元運(yùn)算符(a != null && a != undefined) ? a : b。
class Person {
  // ...
  nick: string | null = null
  getNick(): string {
    return this.nick ?? '';
  }
}
  • 在訪問對(duì)象屬性時(shí),如果該屬性是undefined或者null,可選鏈運(yùn)算符會(huì)返回undefined。在以下示例中,如果一個(gè)Person的實(shí)例有不為空的spouse屬性,且spouse有不為空的nick屬性,則輸出spouse.nick。否則,輸出undefined:
class Person {
  nick: string | null = null
  spouse?: Person

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

let p: Person = new Person('Alice');
p.spouse?.nick; // undefined
  • 程序可劃分為多組編譯單元或模塊。
    每個(gè)模塊都有其自己的作用域,即,在模塊中創(chuàng)建的任何聲明(變量、函數(shù)、類等)在該模塊之外都不可見,除非它們被顯式導(dǎo)出。
    與此相對(duì),從另一個(gè)模塊導(dǎo)出的變量、函數(shù)、類、接口等必須首先導(dǎo)入到模塊中。

  • 可以使用關(guān)鍵字export導(dǎo)出頂層的聲明,在導(dǎo)入時(shí)要加{}。

export class Point {
  x: number = 0
  y: number = 0
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}
export let Origin = new Point(0, 0);
export function Distance(p1: Point, p2: Point): number {
  return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
  • 假設(shè)模塊具有路徑“./utils”和導(dǎo)出實(shí)體“X”和“Y”。
    (1)導(dǎo)入綁定* as A表示綁定名稱“A”,通過A.name可訪問從導(dǎo)入路徑指定的模塊導(dǎo)出的所有實(shí)體:
import * as Utils from './utils'
Utils.X // 表示來自Utils的X
Utils.Y // 表示來自Utils的Y

(2)導(dǎo)入綁定{ ident1, ..., identN }表示將導(dǎo)出的實(shí)體與指定名稱綁定,該名稱可以用作簡單名稱:

import { X, Y } from './utils'
X // 表示來自u(píng)tils的X
Y // 表示來自u(píng)tils的Y

(3)如果標(biāo)識(shí)符列表定義了ident as alias,則實(shí)體ident將綁定在名稱alias下:

import { X as Z, Y } from './utils'
Z // 表示來自Utils的X
Y // 表示來自Utils的Y
X // 編譯時(shí)錯(cuò)誤:'X'不可見
  • import()語法通常稱為動(dòng)態(tài)導(dǎo)入dynamic import,是一種類似函數(shù)的表達(dá)式,用來動(dòng)態(tài)導(dǎo)入模塊。以這種方式調(diào)用,將返回一個(gè)promise。
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
  • 如果在異步函數(shù)中,可以使用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();
}
  • HarmonyOS SDK提供的開放能力(接口)也需要在導(dǎo)入聲明后使用??芍苯訉?dǎo)入接口模塊來使用該模塊內(nèi)的所有接口能力,例如:(這種方式應(yīng)該是過時(shí)了)
import UIAbility from '@ohos.app.ability.UIAbility';
  • 導(dǎo)入Kit下多個(gè)模塊的接口能力。例如:(單個(gè)的包含在這里; 所有的*的方式最好不要用)
import { UIAbility, Ability, Context } from '@kit.AbilityKit';
  • 關(guān)鍵字this只能在類的實(shí)例方法中使用。
class A {
  count: string = 'a'
  m(i: string): void {
    this.count = i;
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容