2024-08-28

HarmonyOS Next应用开发:ArkTS语言介绍

通过介绍ArkTS的一些语法知识,使开发者能够使用ArkTS进行基本的开发。本文假设你有一定的编程经验,对于常见的语法,例如for、while不会过多介绍。

变量声明

以关键字let开头的声明引入变量,声明时数据类型要放到变量后面,并且用冒号“ : ”分隔,声明的变量在程序执行期间可以具有不同的值:

let str1:String = 'hello';
str1 = 'hello,world';

如果一个变量的声明包含了初始值,那么开发者就不需要显式指定其类型,会进行自动类型推断:

let str2 = 'hello, world';

常量声明

以关键字const开头的声明引入只读常量,该常量只能被赋值一次,如果一个常量的声明包含了初始值,同样会进行自动类型推断,对常量重新赋值会造成编译时错误:

const hello: string = 'hello';

类型

Number类型

在ArkTS中,无论是整数类型(如int, long)还是浮点类型(如float, double),都被统一视为number类型。

let n1:number = 119;
let n2:Number = 3.14;
let n3 = 0xF1A7
let n4 = 1e2;
Boolean类型

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

let isDone: boolean = false;
String类型

字符串字面量由单引号(')或双引号(")之间括起来的零个或多个字符组成。字符串字面量还有一特殊形式,是用反向单引号(`)括起来的模板字面量。

let s1 = 'Hello, world!\n';
let s2 = "this is a string";
let a = 'Success';
let s3 = `The result is ${a}`;
Void类型

void类型用于指定函数没有返回值。

function hello():void{
  console.log("Hello");
}
Object类型

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

let o: Object = false;
o= 1;
Array类型
// 通过字面量来创建数组
let names: string[] = ['Alice', 'Bob', 'Carol'];
// 没有元素,显式指定泛型参数为 string
let arr1: string[] = [];
arr1.push('Alice', 'Bob', 'Carol');

// 使用构造函数创建数组
let fruit:Array<string> = new Array('apple', 'banana');
let arr2:Array<string> = new Array();
arr2.push('apple');
arr2.push('banana');

//声明array是一个常量,不可以再指向另一个对象,但是可以给它添加元素
const array = [1,2,3];
// array1 = [1,2];//报错Cannot assign to 'array1' because it is a constant.
array.push(4);
Enum类型

使用枚举常量时必须以枚举类型名称为前缀。

enum ColorSet { Red, Green, Blue }
let c: ColorSet = ColorSet.Red;

常量表达式可以用于显式设置枚举常量的值。

enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 }
let c: ColorSet = ColorSet.Black;
Union类型

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

class Cat {
  // ...
}
class Dog {
  // ...
}
class Frog {
  // ...
}
// Cat、Dog、Frog是一些类型(类或接口)
type Animal = Cat | Dog | Frog | number

// 可以将类型为联合类型的变量赋值为任何组成类型的有效值
let animal: Animal = new Cat();
animal = new Frog();
animal = 42;

可以用不同的机制获取联合类型中特定类型的值。

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方法
}
Aliases类型

Aliases类型为匿名类型(数组、函数、对象字面量或联合类型)提供名称,或为已有类型提供替代名称。

type Matrix = number[][];
type Handler = (s: string, no: number) => string;
type Predicate <T> = (x: T) => boolean;
type NullableObject = Object | null;

let matrix:Matrix = [[1,2],[3,4]];

语句

if语句

条件表达式可以是任何类型。但是对于boolean以外的类型,会进行隐式类型转换:

let s1 = 'Hello';
if (s1) {
  console.log(s1); // 打印“Hello”
}

let s2 = 'World';
if (s2.length != 0) {
  console.log(s2); // 打印“World”
}

let s3 = 0;
if (!s3) {
  console.log(s3+""); // 打印“0”
}

let s4 = '';
if (!s4) {
  console.log(s4+""); // 打印“”
}

let s5 = null;
if (!s5) {
  console.log(s5+""); // 打印“null”
}

let s6 = undefined;
if (!s6) {
  console.log(s6+""); // 打印“undefined”
}
for-of语句

使用for-of语句可遍历数组或字符串:

for (let ch of 'harmonyos') {
  /* process ch */
}
Break语句

使用break语句可以终止循环语句或switch,如果break语句后带有标识符,则将控制流转移到该标识符所包含的语句块之外。

let x = 1
label: while (true) {
  switch (x) {
    case 1:
      // statements
      break label; // 中断while语句
  }
}

switch语句、条件表达式、for语句、while语句、do-while语句、continue语句、throw语句、try-catch语句和其它编程语言基本相似,此处不再过多介绍。

函数

函数声明
函数声明引入一个函数,使用function关键字开头,包含其名称、参数列表(参数类型要放到参数名称后面,并且用冒号“ : ”分隔)、返回类型(放到参数列表后面,并且用冒号“ : ”分隔;如果可以从函数体内推断出函数返回类型,则可在函数声明中省略标注返回类型;不需要返回值的函数的返回类型可以显式指定为void或省略标注。这类函数不需要返回语句。)和函数体。

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

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

在函数声明中,必须为每个参数标记类型。如果参数为可选参数,那么允许在调用函数时省略该参数。函数的最后一个参数可以是rest参数。

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

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

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

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

函数的作用域
函数中定义的变量和其他实例仅可以在函数内部访问,不能从外部访问。

如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。

类声明引入一个新类型,并定义其字段、方法和构造函数。

class Person {
  // 实例字段
 // 为了减少运行时的错误和获得更好的执行性能,
 // ArkTS要求所有字段在声明时或者构造函数中显式初始化。
  firstName: string = ''
  lastName: string = ''
 // 静态字段
  private static numberOfPersons:= 0
  // 构造函数用constructor 关键字声明
  constructor (fn: string, ln: string) {
    this.firstName = fn;
    this.lastName = ln;
    Person.numberOfPersons++;
  }
  // 实例方法
  fullName(): string {
    return this.firstName + ' ' + this.lastName;
  }
  // 静态方法
  static getNumOfPersons():number {
    return Person.numberOfPersons;
  }
}

定义类后,可以使用关键字new创建实例:

let p = new Person('John', 'Smith');

或者,可以使用对象字面量创建实例:

let p:Person = {
  firstName: 'John',
  lastName: 'Smith',
  fullName(): string {
    return this.firstName+ ' ' + this.lastName;
  }
};

getter和setter

setter和getter可用于提供对对象属性的受控访问,在类中可以定义getter或者setter。

在以下示例中,setter用于禁止将_age属性设置为无效值:

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; // 设置无效age值会抛出错误

在类的继承方面仍然是单继承,一个类可以继承另一个类。
类的方法和属性都可以使用可见性修饰符。可见性修饰符包括:private、protected和public。默认可见性为public。

接口

接口声明引入新类型。接口是定义代码协定的常见方式。任何一个类的实例只要实现了特定接口,就可以通过该接口实现多态。接口可以继承其他接口。
接口和其它语言中的使用相差无几,这里就不多赘述了。

Record类型的对象字面量

泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。常用对象字面量来初始化该类型的值,类似于Map或字典的数据结构:

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

this

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

class A {
  count: string = 'a'
  m(i: string): void {
    this.count = i;
  }
}

使用限制:不支持this类型,不支持在函数和类的静态方法中使用this。
示例:

class A {
  n: number = 0
  f1(arg1: this) {} // 编译时错误,不支持this类型
  static f2(arg1: number) {
    this.n = arg1;  // 编译时错误,不支持在类的静态方法中使用this
  }
}

function foo(arg1: number) {
  this.n = i;       // 编译时错误,不支持在函数中使用this
}

关键字this的指向:调用实例方法的对象,正在构造的对象。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容