來源
ArkTS來自TypeScript脆荷,TS就是TypeScript的縮寫时肿。而TypeScript就是來自JavaScript蹄梢,所以所謂的兩種語言其實就是一種語言JavaScript嫉父。當(dāng)然熟掂,還是按照官方的建議缎浇,使用ArkTS就可以了,反正都是JS生態(tài)赴肚。
語言簡介
- let是變量素跺,const是常量二蓝,定義時帶上初始值,可以推斷類型
let hi1: string = 'hello';
let hi2 = 'hello, world';
const hi3 = 'hello, world! can not change';
數(shù)字的類型是number指厌,不用區(qū)分整數(shù)和浮點數(shù)刊愚;默認(rèn)是10進(jìn)制;16進(jìn)制用0x開頭踩验;
boolean類型由true和false兩個邏輯值組成鸥诽。
字符串字面量由單引號(')或雙引號(")之間括起來的零個或多個字符組成(實際使用優(yōu)先用雙引號)。字符串字面量還有一特殊形式箕憾,是用反向單引號(`)括起來的模板字面量牡借。字符串插值用${}
let s1 = 'Hello, world!\n';
let s2 = 'this is a string';
let a = 'Success';
let s3 = `The result is ${a}`;
Object類型是所有引用類型的基類型。任何值袭异,包括基本類型的值(它們會被自動裝箱)钠龙,都可以直接被賦給Object類型的變量。
數(shù)組Array類型
let names: string[] = ['Alice', 'Bob', 'Carol'];
- enum類型御铃,又稱枚舉類型碴里,是預(yù)先定義的一組命名值的值類型,其中命名值又稱為枚舉常量上真。
enum ColorSet { Red, Green, Blue }
let c: ColorSet = ColorSet.Red;
- union類型咬腋,即聯(lián)合類型,是由多個類型組合成的引用類型睡互。聯(liá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 (); // 任何動物都可以睡覺
- Aliases類型為匿名類型(數(shù)組就珠、函數(shù)犀填、對象字面量或聯(lián)合類型)提供名稱,或為已有類型提供替代名稱嗓违。
type Matrix = number[][];
type Handler = (s: string, no: number) => string;
type Predicate <T> = (x: T) => Boolean;
type NullableObject = Object | null;
if 要帶括號,條件可以是任何表達(dá)式图贸,會隱式轉(zhuǎn)換為boolean類型(這點不如Swift)
switch語句的break不應(yīng)該省略蹂季;如果沒有break語句,則執(zhí)行switch中的下一個label對應(yīng)的代碼塊疏日。(這點不如Swift)
使用for-of語句可遍歷數(shù)組或字符串偿洁。
for (let ch of 'a string object') {
/* process ch */
}
- 錯誤處理: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)用中這個參數(shù)被省略了沟优,則會使用此參數(shù)的默認(rèn)值作為實參涕滋。
function multiply(n: number, coeff: number = 2): number {
return n * coeff;
}
multiply(2); // 返回2*2
multiply(2, 3); // 返回2*3
- 函數(shù)的最后一個參數(shù)可以是rest參數(shù)。使用rest參數(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)境包含了這個閉包創(chuàng)建時作用域內(nèi)的任何局部變量增拥。
在下例中啄巧,z是執(zhí)行f時創(chuàng)建的g箭頭函數(shù)實例的引用。g的實例維持了對它的環(huán)境的引用(變量count存在其中)掌栅。因此秩仆,當(dāng)z被調(diào)用時,變量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)用方式。具體方法為忘衍,為同一個函數(shù)寫入多個同名但簽名不同的函數(shù)頭逾苫,函數(shù)實現(xiàn)緊隨其后。
function foo(x: number): void; /* 第一個函數(shù)定義 */
function foo(x: string): void; /* 第二個函數(shù)定義 */
function foo(x: number | string): void { /* 函數(shù)實現(xiàn) */
}
foo(123); // OK枚钓,使用第一個定義
foo('aa'); // OK铅搓,使用第二個定義
- 為了減少運行時的錯誤和獲得更好的執(zhí)行性能,ArkTS要求所有字段在聲明時或者構(gòu)造函數(shù)中顯式初始化搀捷。如果可能為空星掰,要加?
class Person {
name?: string // 可能為`undefined`
setName(n:string): void {
this.name = n;
}
// 編譯時錯誤:name可以是"undefined"嫩舟,所以將這個API的返回值類型標(biāo)記為string
getNameWrong(): string {
return this.name;
}
getName(): string | undefined { // 返回類型匹配name的類型
return this.name;
}
}
let jack = new Person();
// 假設(shè)代碼中沒有對name賦值氢烘,例如調(diào)用"jack.setName('Jack')"
// 編譯時錯誤:編譯器認(rèn)為下一行代碼有可能會訪問undefined的屬性,報錯
jack.getName().length; // 編譯失敗
jack.getName()?.length; // 編譯成功家厌,沒有運行時錯誤
- setter和getter可用于提供對對象屬性的受控訪問播玖。
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值會拋出錯誤
- 關(guān)鍵字super可用于訪問父類的實例字段、實例方法和構(gòu)造函數(shù)饭于。在實現(xiàn)子類功能時蜀踏,可以通過該關(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 -可在此處使用
/* 填充矩形 */
}
}
- 子類可以重寫其父類中定義的方法的實現(xiàn)。重寫的方法必須具有與原始方法相同的參數(shù)類型和相同或派生的返回類型掰吕。
class RectangleSize {
// ...
area(): number {
// 實現(xiàn)
return 0;
}
}
class Square extends RectangleSize {
private side: number = 0
area(): number {
return this.side * this.side;
}
}
- 通過重載簽名果覆,指定方法的不同調(diào)用。具體方法為殖熟,為同一個方法寫入多個同名但簽名不同的方法頭局待,方法實現(xiàn)緊隨其后。
class C {
foo(x: number): void; /* 第一個簽名 */
foo(x: string): void; /* 第二個簽名 */
foo(x: number | string): void { /* 實現(xiàn)簽名 */
}
}
let c = new C();
c.foo(123); // OK,使用第一個簽名
c.foo('aa'); // OK钳榨,使用第二個簽名
- 我們可以通過編寫重載簽名舰罚,指定構(gòu)造函數(shù)的不同調(diào)用方式。具體方法為重绷,為同一個構(gòu)造函數(shù)寫入多個同名但簽名不同的構(gòu)造函數(shù)頭沸停,構(gòu)造函數(shù)實現(xiàn)緊隨其后。
class C {
constructor(x: number) /* 第一個簽名 */
constructor(x: string) /* 第二個簽名 */
constructor(x: number | string) { /* 實現(xiàn)簽名 */
}
}
let c1 = new C(123); // OK昭卓,使用第一個簽名
let c2 = new C('abc'); // OK愤钾,使用第二個簽名
- 對象字面量是一個表達(dá)式,可用于創(chuàng)建類實例并提供一些初始值候醒。它在某些情況下更方便能颁,可以用來代替new表達(dá)式。(JS對象的本質(zhì)是一個Map)
class C {
n: number = 0
s: string = ''
}
let c: C = {n: 42, s: 'foo'};
- 泛型Record<K, V>用于將類型(鍵類型)的屬性映射到另一個類型(值類型)倒淫。常用對象字面量來初始化該類型的值:類型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對的便捷寫法返干。以下表達(dá)方式是等價的:
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ù)可編寫更通用的代碼。比如返回數(shù)組最后一個元素的函數(shù):
function last<T>(x: T[]): T {
return x[x.length - 1];
}
// 顯式設(shè)置的類型實參
last<string>(['aa', 'bb']);
last<number>([1, 2, 3]);
// 隱式設(shè)置的類型實參
// 編譯器根據(jù)調(diào)用參數(shù)的類型來確定類型實參
last([1, 2, 3]);
- 泛型類型的類型參數(shù)可以設(shè)置默認(rèn)值癌淮。這樣可以不指定實際的類型實參躺坟,而只使用泛型類型名稱。下面的示例展示了類和函數(shù)的這一點乳蓄。
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();
// 此函數(shù)在語義上等價于下面的調(diào)用
foo<number>();
- 可以為空值的變量定義為聯(lián)合類型T | null咪橙。
let x: number | null = null;
x = 1; // ok
x = null; // ok
if (x != null) { /* do something */ }
- 空值合并二元運算符??用于檢查左側(cè)表達(dá)式的求值是否等于null或者undefined。如果是虚倒,則表達(dá)式的結(jié)果為右側(cè)表達(dá)式匣摘;否則,結(jié)果為左側(cè)表達(dá)式裹刮。換句話說,a ?? b等價于三元運算符(a != null && a != undefined) ? a : b庞瘸。
class Person {
// ...
nick: string | null = null
getNick(): string {
return this.nick ?? '';
}
}
- 在訪問對象屬性時捧弃,如果該屬性是undefined或者null,可選鏈運算符會返回undefined。在以下示例中违霞,如果一個Person的實例有不為空的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
程序可劃分為多組編譯單元或模塊。
每個模塊都有其自己的作用域眼五,即妆艘,在模塊中創(chuàng)建的任何聲明(變量、函數(shù)看幼、類等)在該模塊之外都不可見批旺,除非它們被顯式導(dǎo)出。
與此相對诵姜,從另一個模塊導(dǎo)出的變量汽煮、函數(shù)、類棚唆、接口等必須首先導(dǎo)入到模塊中暇赤。可以使用關(guān)鍵字export導(dǎo)出頂層的聲明,在導(dǎo)入時要加{}宵凌。
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)出實體“X”和“Y”鞋囊。
(1)導(dǎo)入綁定* as A表示綁定名稱“A”,通過A.name可訪問從導(dǎo)入路徑指定的模塊導(dǎo)出的所有實體:
import * as Utils from './utils'
Utils.X // 表示來自Utils的X
Utils.Y // 表示來自Utils的Y
(2)導(dǎo)入綁定{ ident1, ..., identN }表示將導(dǎo)出的實體與指定名稱綁定摆寄,該名稱可以用作簡單名稱:
import { X, Y } from './utils'
X // 表示來自utils的X
Y // 表示來自utils的Y
(3)如果標(biāo)識符列表定義了ident as alias失暴,則實體ident將綁定在名稱alias下:
import { X as Z, Y } from './utils'
Z // 表示來自Utils的X
Y // 表示來自Utils的Y
X // 編譯時錯誤:'X'不可見
- import()語法通常稱為動態(tài)導(dǎo)入dynamic import,是一種類似函數(shù)的表達(dá)式微饥,用來動態(tài)導(dǎo)入模塊逗扒。以這種方式調(diào)用,將返回一個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)該是過時了)
import UIAbility from '@ohos.app.ability.UIAbility';
- 導(dǎo)入Kit下多個模塊的接口能力始锚。例如:(單個的包含在這里刽酱; 所有的*的方式最好不要用)
import { UIAbility, Ability, Context } from '@kit.AbilityKit';
- 關(guān)鍵字this只能在類的實例方法中使用。
class A {
count: string = 'a'
m(i: string): void {
this.count = i;
}
}