鴻蒙 ArkTS 基礎語法

白乾涛發表於2024-11-03

本文地址


目錄

目錄
  • 目錄
  • 鴻蒙 ArkTS 基礎語法
    • 型別
    • 運算子
    • 語句
    • 函式
    • 介面
    • 泛型
    • 空安全
    • 模組匯入匯出

鴻蒙 ArkTS 基礎語法

官方文件

型別

以關鍵字let宣告引入變數,以關鍵字const宣告引入只讀常量

let hi: string = 'hello';
const hello: string = 'hello';

ArkTS提供numberNumber型別,任何整數和浮點數都可以被賦給此型別的變數。

string代表字元序列;可以使用跳脫字元來表示字元。可以使用單引號'或雙引號"或反引號。只有反引號支援字串模板,

let s1 = 'Hello, world!\n';
let s2 = "Success";
let s3 = `s1: ${s1}`;

void型別用於指定函式沒有返回值。此型別只有一個值,同樣是void。由於void是引用型別,因此它可以用於泛型型別引數

class A <T> {}
let instance: A <void>

Object型別是所有引用型別的基型別。任何值,包括基本型別的值(它們會被自動裝箱),都可以直接被賦給Object型別的變數。

array,即陣列。

enum,列舉型別,是預先定義的一組命名值的值型別,其中命名值又稱為列舉常量。常量表示式可以用於顯式設定列舉常量的值。

union,即聯合型別,是由多個型別組合成的引用型別。

type Animal = Cat | Dog | Frog | number;

let animal: Animal = new Cat();
animal = new Frog();
animal = 42;

if (animal instanceof Frog) {} // 判斷具體是哪種型別

運算子

===:如果兩個運算元嚴格相等(型別也要相同),則返回true
==:如果兩個運算元相等,則返回true

語句

if 語句:條件表示式可以是任何型別。但是對於boolean以外的型別,會進行隱式型別轉換

if ('Hello') {
  console.log("Hello");
}

if (10086) {
  console.log("Hello");
}

switch 語句:case、break、default

for 語句:使用for-of語句可遍歷陣列或字串

for (let i = 0; i < 10; i += 2) {}
for (let ch of 'a string object') {}

break 語句可以終止迴圈語句或switch。break label 語句可以將控制流轉移到該識別符號所包含的語句塊之外。

異常處理:throw、try、catch、finally

throw new Error('this error')

函式

y 有預設值,z 為可選引數

function add(x: string, y: string = "-", z?: string): string {
  return x + y + z
}

add("b") // "b-undefined" 
add("b", "q") // "bqundefined"
add("b", "q", "t") // "bqt" 

函式的最後一個引數可以是rest引數。

function sum(...numbers: number[]): number {}

sum();
sum(1);
sum(1, 2, 3);

函式型別

type XX = (x: number, y: number) => number // 函式型別

function do_action(f: XX) {
    let result = f(2, 3); // 呼叫函式
    console.log(result.toString())
}

do_action(Math.max); // 3
do_action(Math.min); // 2
do_action(Math.pow); // 8

箭頭函式,又名Lambda函式

閉包。閉包是由函式及宣告該函式的環境組合而成的。該環境包含了這個閉包建立時作用域內的任何區域性變數。

function f(): () => number {
    let count = 0;
    let g = (): number => {
        count++;
        console.log(count)
        return count;
    };
    return g;
}

let z = f();
z(); // 返回:1
z(); // 返回:2

函式過載:為同一個函式寫入多個同名但簽名不同的函式頭,函式實現緊隨其後

function foo(x: number): void;            /* 第一個函式定義 */
function foo(x: string): void;            /* 第二個函式定義 */
function foo(x: number | string): void {} /* 函式實現 */

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

可以使用關鍵字 new 建立例項,也可以使用物件字面量建立例項

關鍵字this只能在類的例項方法、構造方法中使用。 不支援 this 型別

class Person {
    name: string = ''; // 例項欄位,預設可見性為 public
    private surname: string = ''; // 私有欄位
    static numberX = 0; // 靜態欄位,靜態方法同理

    constructor(n: string, sn: string) { // 建構函式
        this.name = n;
        this.surname = sn;
        Person.numberX++;
    }
    
    fullName(): string { // 方法
        return this.name + ' ' + this.surname;
    }
}

let p1 = new Person("bat", "hh")
let p2 = {
    n: "bqt",
    sn: "hh"
}

ArkTS要求所有欄位在宣告時或者建構函式中顯式初始化。這和標準TS中的strictPropertyInitialization模式一樣。

settergetter 可用於提供對物件屬性的受控訪問。

屬性欄位只是 getter/setter對 的便捷寫法。

class Person {
    private _age: number = 0;
    get age(): number { return this._age; }
    set age(x: number) {
        this._age = x < 0 ? 0 : x;
    }
}

let p1 = new Person()
p1.age = -1
console.log(p1.age)

繼承與實現:extends、implements、protected、super、override

建構函式過載,和普通的函式過載語法一樣

class C {
    constructor(x: number)             /* 第一個簽名 */
    constructor(x: string)             /* 第二個簽名 */
    constructor(x: number | string) {  /* 實現簽名 */
    }
}
let c1 = new C(123);   // OK,使用第一個簽名
let c2 = new C('abc'); // OK,使用第二個簽名

介面

介面屬性可以是欄位、getter、setter或getter和setter組合的形式。

介面也可以繼承其他介面。

interface X { }

interface Style extends X {
    color: string      // 屬性
    siez: number
    someMethod(): void // 方法,返回值型別即使是 void 也不能省略
}

class A implements Style {
    color: string = '';             // 重寫屬性的第一種方式
    get siez(): number { return 1 };// 重寫屬性的第二種方式
    set siez(x: number) { };
    someMethod() { }
}

泛型

泛型型別的型別引數可以設定預設值。在泛型函式呼叫中,型別實參可以顯式或隱式設定

class Animal<T> { } // 泛型類和介面
let a = new Animal<string>();

class A { }
class B<K extends A, V = string> { name: K | undefined }
let b = new B<A, number>()
let c = new B<A>()

function last<T>(x: T[]): T {} // 泛型函式
last<number>([1, 2, 3]); // 顯式設定的型別實參
last([1, 2, 3]); // 隱式設定的型別實參

泛型Record<K, V>用於將型別(鍵型別)的屬性對映到另一個型別(值型別)。常用物件字面量來初始化該型別的值。

型別K可以是字串型別或數值型別,而V可以是任何型別。

let map: Record<string, number> = {
  'John': 25,
  'Mary': 21,
}

map['John']; // 25

空安全

預設情況下,ArkTS中的所有型別都是不可為空
的,因此型別的值不能為空。這類似於TypeScript的嚴格空值檢查模式strictNullChecks,但規則更嚴格。

let x: number = null;    // 編譯時錯誤
let y: string = null;    // 編譯時錯誤
let z: number[] = null;  // 編譯時錯誤

可以為允許空值的變數定義為聯合型別 T | null

let x: number | null = null;
x = 1;    // ok
x = null; // ok
if (x != null) {}

字尾運算子 ! 可用於斷言其運算元為非空。

function foo(a: A | null) {
  a.value;   // 編譯時錯誤:無法訪問可空值的屬性
  a!.value;  // 編譯透過,如果執行時a的值為空,則發生執行時異常
}

空值合併二元運算子 ??

a ?? b等價於三元運算子 (a != null && a != undefined) ? a : b

在訪問物件屬性時,如果該屬性是 undefined 或者 null,可選鏈運算子會返回 undefined。

// 返回型別必須為三者的聯合型別,因為該方法可能返回 null 或者 undefined
getNick(): string | null | undefined {
    return this.spouse?.nick;
}

模組匯入匯出

程式可劃分為多組編譯單元或模組

頂層語句是指在模組的最外層直接編寫的語句,這些語句不被包裹在任何函式、類、塊級作用域中。頂層語句包括變數宣告、函式宣告、表示式等。

每個模組都有其自己的作用域,即,在模組中建立的任何宣告(變數、函式、類等)在該模組之外都不可見,除非它們被顯式匯出。

匯出。可以使用關鍵字 export 匯出頂層的宣告。未匯出的宣告名稱被視為私有名稱,只能在宣告該名稱的模組中使用。

export class Point {}
export let Origin = new Point(0, 0);
export function show(): number {}

靜態匯入。匯入宣告用於匯入從其他模組匯出的實體,並在當前模組中提供其繫結。

import * as Utils from './utils' // 匯入繫結
Utils.X // 表示來自Utils的X
Utils.Y // 表示來自Utils的Y
import { X, Y } from './utils' // 將匯出的實體與指定名稱繫結
X // 表示來自utils的X
Y // 表示來自utils的Y

動態匯入:根據條件匯入模組或者按需匯入模組

import('modulePath') // 載入模組,並返回一個包含其所有匯出的模組物件
    .then(obj => <module object>)
    .catch(err => <loading error, e.g. if no such module>)

匯入 HarmonyOS SDK

HarmonyOS SDK 提供的開放能力也需要在匯入宣告後使用。

SDK 對同一個 Kit 下的介面模組進行了封裝,開發者在示例程式碼中可透過匯入 Kit 的方式來使用 Kit 所包含的介面能力。其中,Kit 封裝的介面模組可檢視 SDK 目錄下 Kit 子目錄中各 Kit 的定義。

透過匯入 Kit 方式使用開放能力有三種方式:

  • 匯入單個模組的介面能力:import { UIAbility } from '@kit.AbilityKit';
  • 匯入多個模組的介面能力:import { UIAbility, Ability, Context } from '@kit.AbilityKit';
  • 匯入所有模組的介面能力:import * as xxx from '@kit.AbilityKit';

方式三可能會匯入過多無需使用的模組,導致編譯後的 HAP 包太大,佔用過多資源,請謹慎使用。

2024.11.03

相關文章