鸿蒙-TypeScript语法

十念  论坛元老 | 2024-11-15 08:41:47 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1023|帖子 1023|积分 3069

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1. 概述



HarmonyOS 应用的主要开发语言是 ArkTS,它由 TypeScript(简称TS)扩展而来,在继承TypeScript语法的底子上举行了一系列优化,使开发者可以或许以更简便、更自然的方式开发应用。
留意:TypeScript 自己也是由另一门语言 JavaScript 扩展而来,它主要是在JavaScript的底子上添加了静态类型定义。因此三者的关系如下图所示

2. TypeScript 快速入门

TypeScript提供了一个线上的 Playground 供训练使用,地址为TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript。



2.1. 声明

变量声明

常量声明
let用于声明变量,而const用于声明常量,两者的区别是:变量在赋值后可以修改,而常量在赋值后便不能再修改。
  1. let a:number = 100
  2. const b:number = 200;
复制代码
类型推断
如果一个变量或常量的声明包罗了初始值,TS 便可以根据初始值举行类型推断,此时我们就可以不消显式的指定其类型,比方:
  1. let c = 60;
  2. console.log(typeof c); //number
复制代码
2.2. 常用数据类型

number类型
number表现数字,包括整数和浮点数,比方: 340、-23 、29.5、-13.4
  1. let a :number = 340
  2. let b :number = -23
  3. let c :number = 29.5
  4. let d :number = -13.4
复制代码
string类型
string表现字符串,比方: 你好、hello
  1. let a:string = '你好'
  2. let b:string = 'hello'
复制代码
boolean类型
boolean表现布尔值,可选值为:true、false
  1. let isOpen:boolean = true
  2. let isDone:boolean = false
复制代码
数组类型
数组类型定义由两部门组成,元素类型[],比方number[]表现数字数组,string[]表现字符串数组,数组类型的变量可由数组字面量——[item1,item2,item3]举行初始化。
  1. let a: number[] = []
  2. let b: string[] = ['你好', 'hello']
复制代码
对象类型
对象(object)类型的声明很简朴,只需声明属性名称和属性类型即可,比方{id:number,name:string},对象类型的变量可以通过对象字面量——{id:1,name:'zhangsan'}举行初始化。
  1. let person: { id: number, name: string } = { id: 1, name: 'zhangsan' };
复制代码

2.3. 函数



可选参数:可选参数通过参数名后的?举行标识,比方下面的gender?参数。
  1. function getPersonInfo(name: string, age: number, gender?: string) {
  2.     if (!gender) {
  3.         gender = '未知'
  4.     }
  5.     return `name:${name},age:${age},gender:${gender}`;
  6. }
  7. let p1 = getPersonInfo('zhagnsan', 10, '男')
  8. let p2 = getPersonInfo('lisi', 15);
  9. console.log(p1);
  10. console.log(p2);
复制代码
默认参数:可在函数的参数列表为参数指定默认值,如以下案例中的gender: string='未知'参数。
  1. function getPersonInfo(name: string, age: number, gender: string='未知') {
  2.     return `name:${name},age:${age},gender:${gender}`;
  3. }
  4. let p1 = getPersonInfo('zhagnsan', 10, '男')
  5. let p2 = getPersonInfo('lisi', 15);
  6. console.log(p1);
  7. console.log(p2);
复制代码
联合类型:一个函数可能用于处理差别类型的值,这种环境可以使用联合类型,比方以下案例中的message: number | string
  1. function printNumberOrString(message: number | string) {
  2.   console.log(message)
  3. }
  4. printNumberOrString('a')
  5. printNumberOrString(1)
复制代码
任意类型:若函数需要处理任意类型的值,则可以使用any类型,比方以下案例中的message: any
  1. function print(message:any) {
  2.   console.log(message)
  3. }
  4. print('a')
  5. print(1)
  6. print(true)
复制代码
特别类型:若函数没有返回值,则可以使用void作为返回值类型,其含义为空。
  1. function test(): void {
  2.     console.log('hello');
  3. }
复制代码
类型推断:函数的返回值类型可根据函数内容推断出来,因此可以省略不写。
  1. function test() {
  2.     console.log('hello');
  3. }
  4. function sum(a: number, b: number) {
  5.     console.log(a + b);
  6. }
复制代码
匿名函数:匿名函数的语法布局简便,特别适用于简朴且仅需一次性使用的场景。
  1. let numbers: number[] = [1, 2, 3, 4, 5]
  2. numbers.forEach(function (number) {
  3.     console.log(number);
  4. })
复制代码
留意:匿名函数可以或许根据上下文推断出参数类型,因此参数类型可以省略。

箭头函数:匿名函数的语法还可以进一步的简化,只保留参数列表和函数体两个焦点部门,两者用=>符号连接。
  1. let numbers: number[] = [1, 2, 3, 4, 5]
  2. numbers.forEach((num) => { console.log(num) })
复制代码

2.4. 类(class)

概述:
类(class)是对象的蓝图或模板,它定义了对象的属性(数据)和行为(方法)。通过类可以创建多个具有相似布局和行为的对象。比方定义一个 Person类,其对象可以有张三、李四等等。

通过一个简朴案例,学习一下类的定义语法


示例代码:
  1. class Person {
  2.     id: number;
  3.     name: string;
  4.     age: number = 18;
  5.     constructor(id: number, name: string) {
  6.         this.id = id;
  7.         this.name = name;
  8.     }
  9.     introduce(): string {
  10.         return `hello,I am ${this.name},and I am ${this.age} years old.`
  11.     }
  12. }
复制代码

对象创建:创建对象的关键字为new,具体语法如下
  1. let person = new Person(1,'zhangsan,10);
复制代码
对象属性的访问
  1. console.log(person.name); //读
  2. person.name = 'lisi'; //写
  3. console.log(person.name);
复制代码
对象方法的调用:对象创建后,便可通过对象调用类中声明的方法,如下
  1. let intro = person.introduce();
  2. console.log(intro);
复制代码

静态成员
Typescript 中的类中可以包罗静态成员(静态属性和静态方法),静态成员从属于类自己,而不属于某个对象实例。静态成员通用用于定义一些常量,大概工具方法。



  • 声明静态成员:定义静态成员需要使用static关键字。
  1. class Constants{
  2.     static count:number=1;
  3. }
  4. class Utils{
  5.     static toLowerCase(str:string){
  6.         return str.toLowerCase();
  7.     }
  8. }
  9. console.log(Constants.count);
  10. console.log(Utils.toLowerCase('Hello World'));
复制代码


  • 使用静态成员:静态成员无需通过对象实例访问,直接通过类自己访问即可。
  1. console.log(Constants.count);
  2. console.log(Utils.toLowerCase('Hello World'));
复制代码
继承:
继承是面向对象编程中的重要机制,允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。子类可以直接使用父类的特性,并根据需要添加新的特性或覆盖现有的特性。这种机制赋予面向对象程序良好的扩展性。
下面通过一个例子演示继承的特性
  1. class Student extends Person {
  2.     classNumber: string;
  3.     constructor(id: number, name: string, age: number, classNumber: string) {
  4.         super(id, name, age);
  5.         this.classNumber = classNumber;
  6.     }
  7.     introduce(): string {
  8.         return `hello,I am ${this.name},and I am ${this.age} years old, and I am a student`
  9.     }
  10. }
  11. let student = new Student(1,'xiaoming',10,'三年二班');
  12. console.log(student.introduce());
复制代码


  • 关键字:extends
  • 新增属性:classNumber:string;
  • 覆盖父类方法:introduce
  • 构造器:子类构造器中需调用super(父类构造器)对继承的父类属性举行初始化。

权限修饰符
权限修饰符用于控制类成员(属性、方法等)的访问权限。它们有助于维护代码的封装性和安全性。TypeScript提供了三种访问修饰符,分别是 publicprivateprotected


  • public :公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的。
  • private:私有的,只能在声明它的类中的被访问。
  • protected:受掩护的,只能在声明它的类和其子类中被访问。

2.5. 接口(interface)

概述
接口(interface)是面向对象编程中的另一个重要概念。接口通常会作为类(class)的一种契约或规范,确保类实现了特定的行为或功能。通常环境下,接口中只会包罗属性和方法的声明,而不包罗具体的实现细节,具体的细节由实在现类完成。

接口定义:接口使用interface关键字定义,具体如下
  1. interface Person {
  2.     id: number;
  3.     name: string;
  4.     age: number;
  5.     job: string;
  6.     introduce(): void;
  7. }
复制代码
接口实现
接口的实现需要用到implements关键字,实现类中,需要包罗接口属性的赋值逻辑,以及接口方法的实现逻辑。
  1. class Teacher implements Person {
  2.     id: number;
  3.     name: string;
  4.     age: number;
  5.     job: string = 'Teacher';
  6.     constructor(id: number, name: string, age: number) {
  7.         this.id = id;
  8.         this.name = name;
  9.         this.age = age;
  10.     }
  11.     introduce(): void {
  12.         console.log(`Hello,I am ${this.name}`);
  13.     }
  14. }
复制代码
作用
在传统的面向对象编程的场景中,接口主要用于计划和构造代码,使代码更加容易扩展和维护。下面举例说明。假如如今需要实现一个订单支付体系,按照面向对象编程的习惯,起首需要定义一个订单类(Order),如下
  1. class Order {
  2.     total_amount: number;
  3.     constructor(total_amount: number) {
  4.         this.total_amount = total_amount;
  5.     }
  6.     pay() {
  7.         console.log(`Pay:${this.total_amount}`);
  8.     }
  9. }
复制代码
很容易预想到,订单需要未来可能需要支持多种支付方式,为了方便后期让代码支持新的支付方式,我们可以对代码举行如下改造。起首定义一个支付策略的接口,接口中声明了一个pay方法,用来规范实现类必须实现支付逻辑。
  1. interface PaymentStrategy {
  2.     pay(amount: number): void;
  3. }
复制代码
然后在订单类中增长一个PaymentStrategy的属性,而且在订单类中的pay方法中调用PaymentStrategy的pay方法,如下
  1. class Order {
  2.     total_amount: number;
  3.     paymentStrategy: PaymentStrategy;
  4.     constructor(total_amount: number, paymentStrategy: PaymentStrategy) {
  5.         this.total_amount = total_amount;
  6.         this.paymentStrategy = paymentStrategy;
  7.     }
  8.     pay() {
  9.         this.paymentStrategy.pay(this.total_amount);
  10.     }
  11. }
复制代码
如许改造完之后,就可以很容易的在不改变现有代码的环境下,支持新的支付方式了。
比如如今需要支持AliPay,那我们就可以创建AliPay这个类(class)并实现(implement)PaymentStrategy这个接口,如下
  1. class AliPay implements PaymentStrategy {
  2.     pay(amount: number): void {
  3.         console.log(`AliPay:${amount}`);
  4.     }
  5. }
复制代码
如许一来,之后创建的订单就可以使用AliPay这个支付方式了。
  1. let order = new Order(1000,new AliPay());
  2. order.pay();
复制代码

TS 中的接口的特别性
TypeScript 中的接口是一个非常机动的概念,除了用作类的规范,让类去实现之外,也常用于直接形貌对象的类型,比方,现有一个方法的定义如下
  1. function getPersonInfo(person: { id: number, name: string, age: number }) {
  2.     console.log(`[id:${person.id},name:${person.name},age:${person.age}]`);
  3. }
复制代码
可以看到该函数的参数类型为一个一般对象:{ id: number, name: string, age: number },此时就可以声明一个接口来形貌参数类型,如下,如许一来,函数定义就会更加简便明了。
  1. interface Person {
  2.     id: number;
  3.     name: string;
  4.     age: number;
  5. }
  6. function getPersonInfo(person: Person) {
  7.     console.log(`[id:${person.id},name:${person.name},age:${person.age}]`);
  8. }
复制代码
为使接口使用起来更加机动,TypeScript提出了可选属性的概念,语法如下
  1. interface Person {
  2.     id: number;
  3.     name: string;
  4.     age?: number;
  5. }
复制代码
上述接口中的age字段就是一个可选属性,在声明该接口类型的对象时,便可根据实际环境选择性的包罗大概不包罗 age字段,如下
  1. getPersonInfo({ id: 1, name: 'zhangsan', age: 10 })
  2. getPersonInfo({ id: 2, name: 'lisi' })
复制代码
2.6. 枚举

概述
枚举(Enumeration)是一种编程语言中常见的数据类型,用于定义一组有限的定名常量,常用于表现特定的状态、类型或选项,比方方向(上、下、左、右)、季候(春、夏、秋、冬)等。
  1. enum Direction {
  2.     UP,
  3.     BOTTOM,
  4.     LEFT,
  5.     RIGHT
  6. }
  7. function move(direction: Direction) {
  8.     switch (direction) {
  9.         case Direction.UP:
  10.             console.log('向上移动');
  11.             break;
  12.         case Direction.BOTTOM:
  13.             console.log('向下移动');
  14.             break;
  15.         case Direction.LEFT:
  16.             console.log('向左移动');
  17.             break;
  18.         case Direction.RIGHT:
  19.             console.log('向右移动');
  20.             break;
  21.         default:
  22.             console.log('原地不动')
  23.             break;
  24.     }
  25. }
  26. move(Direction.UP);
复制代码
枚举的使用记着两个原则

  • 枚举值的访问
像访问对象属性一样访问枚举值,比方Direction.UP

  • 枚举值的类型
枚举值的类型为enum的名称,比方Direction.UP和Direction. BOTTOM等值的类型都是Direction

枚举原理
默认环境下,每个属性的值都是数字,而且从 0 开始递增,比方上述案例中的Direction枚举中,Direction.UP的值为0,Direction.BOTTOM的值为1,依次类推,具体如下
  1. console.log(Direction.UP) //0
  2. console.log(Direction.BOTTOM) //1
  3. console.log(Direction.LEFT) //2
  4. console.log(Direction.RIGHT) //3
复制代码
除了使用默认的数字作为属性的值,我们还能手动为每个属性赋值,比方
  1. enum Direction {
  2.     UP = 1,
  3.     BOTTOM = 2,
  4.     LEFT = 3,
  5.     RIGHT = 4
  6. }
  7. console.log(Direction.UP) //1
  8. console.log(Direction.BOTTOM) //2
  9. console.log(Direction.LEFT) //3
  10. console.log(Direction.RIGHT) //4
复制代码
再比方
  1. enum Direction {
  2.     UP = 'up',
  3.     BOTTOM = 'bottom',
  4.     LEFT = 'left',
  5.     RIGHT = 'right'
  6. }
  7. console.log(Direction.UP) //up
  8. console.log(Direction.BOTTOM) //bottom
  9. console.log(Direction.LEFT) //left
  10. console.log(Direction.RIGHT) //right
复制代码
留意:
多数环境下,我们只是用枚举来表现几种差别的状态,以便在差别的状态下采取差别的举措,这时一般无需关注每个属性具体的值。
2.7. 模块化

概述
模块化是将复杂的程序拆解为多个独立的文件单位,每个文件被称为一个模块。在 TypeScript 中,默认环境下,每个模块都拥有自己的作用域,这意味着在一个模块中声明的任何内容(如变量、函数、类等)在该模块外部是不可见的,除非明确导出。同时,为了在一个模块中使用其他模块的内容,必须先将这些内容显式导入到当前模块中。


导出:导出须使用export关键字,语法如下
  1. export function hello() {
  2.     console.log('hello module A');
  3. }
  4. export const str = 'hello world';
  5. const num = 1;
复制代码
导入:导入须使用import关键字,语法如下
  1. import { hello, str } from './moduleA';
  2. hello();
  3. console.log(str);
复制代码
避免定名冲突
若多个模块中具有定名雷同的变量、函数等内容,将这些内容导入到同一模块下就会出现定名冲突。比方,在上述案例的底子上,又增长了一个 moduleC,内容如下
  1. export function hello() {
  2.     console.log('hello module C');
  3. }
  4. export const str = 'module C';
复制代码
moduleB 同时引入 moduleA 和 moduleC 的内容,如下,显然就会出定名冲突
  1. import { hello, str } from "./moduleA";
  2. import { hello, str } from "./moduleC";
  3. hello() //?
  4. console.log(str); //?
复制代码
有多种方式可以用来办理定名冲突,下面逐一介绍


  • 导入同时举行重定名
  1. import { hello as helloFromA, str as strFromA } from "./moduleA";
  2. import { hello as helloFromC, str as strFromC } from "./moduleC";
  3. helloFromA();
  4. console.log(strFromA);
  5. helloFromC();
  6. console.log(strFromC);
复制代码


  • 创建模块对象
上述导入重定名的方式可以或许很好的办理定名冲突的问题,但是当冲突内容较多时,这种写法会比较冗长。除了导入重定名外,还可以将某个模块的内容同一导入到一个模块对象上,如许就能简便有效的办理定名冲突的问题了,具体语法如下
  1. import * as A from "./moduleA";
  2. import * as C from "./moduleC";
  3. A.hello();
  4. console.log(A.str);
  5. C.hello();
  6. console.log(C.str);
复制代码

除了上述导入导出的语法之外,还有一种语法,叫做默认导入导出,这种语法相对简便一些。


  • 默认导出:默认导出允许一个模块指定一个(最多一个)默认的导出项,语法如下
  1. export default function hello(){
  2.     console.log('moduleA');
  3. }
复制代码
默认导出支持匿名导出项,语法如下
  1. export default function () {
  2.     console.log('moduleB');
  3. }
复制代码


  • 默认导入
由于每个模块最多有一个默认导出,因此默认导入无需指定导入项的原名称,而且无需使用{}。
  1. import helloFromA from "./moduleA";
  2. import helloFromB from "./moduleB";
复制代码
上述语法相当于以下语法的简写
  1. import { default as helloFromA } from "./moduleA";
  2. import { default as helloFromB } from "./moduleB";
复制代码
2.8. 装饰器

概述
在TypeScript中,装饰器是一种特别类型的声明,可以被附加到类,属性,方法上。装饰器的焦点头脑是在尽量不改变原始类的定义的环境下,为类添加新的特性。
装饰器使用@Expression的形式。其中,Expression为一个函数,这个函数负责定义为类添加的新特性,其会在运行时被调用。
ArkTS 提供了多种装饰器,同时在鸿蒙应用的开发中我们也会大量使用这些装饰器,因此学习装饰器语法,对于明白鸿蒙应用的执行原理有很大资助。

装饰器的分类
按照声明位置的差别,装饰器可以分为类装饰器、方法装饰器和属性装饰器等,差别装饰器可用于实现差别的功能。


  • 类装饰器:
类装饰器可以拦截并修改类的构造函数,这使得我们可以在实例化对象时增长一些额外的逻辑。
  1. @ClassDecorator
  2. class A {
  3. }
  4. /**
  5. * 装饰器函数
  6. * 在第一次引用A类时执行
  7. * @param target  被装饰的类
  8. */
  9. function ClassDecorator (target) {
  10.   // 给目标类添加静态属性
  11.   target.xxx = 'abc'
  12. }
  13. console.log((A as any).xxx)  // abc
复制代码



  • 方法装饰器
使用方法装饰器可以拦截并修改所装饰的方法,这使得我们可以在调用该方法之前或之后执行一些额外的逻辑。
  1. class A {
  2.   @MethodDecorator
  3.   hello(){
  4.     console.log('hello()');
  5.   }
  6. }
  7. /**
  8. * 方法装饰器
  9. * 在第一次调用方法前执行
  10. * @param target 方法所属类的原型对象
  11. * @param name 方法名
  12. * @param descriptor 方法属性对应的描述符对象
  13. */
  14. function MethodDecorator (target: object, name: string, descriptor: PropertyDescriptor) {
  15.   console.log(`${name}方法将要第一次调用了`, target, name, descriptor);
  16. }
  17. const a = new A()
  18. a.hello()
复制代码



  • 属性装饰器
属性装饰器可以拦截对属性的读写操纵,并在这些操纵之前或之后执行一些额外的逻辑。
  1. class A {
  2.   @PropertyDecorator
  3.   name: string;
  4. }
  5. /**
  6. * 属性装饰器
  7. * 在第一次创建对象内部初始化属性时执行
  8. * @param target 属性所属类的原型对象
  9. * @param name 属性名
  10. */
  11. function PropertyDecorator (target: object, name: string) {
  12.   console.log(`将要第一次操作${name}属性`, target, name);
  13. }
  14. const a = new A() // 内部会将name属性添加给a对象,自动调用PropertyDecorator
复制代码
简朴案例
下面通过一个简朴的案例,演示装饰器的作用,比方如今需要监听某一个属性的变化,当其发生变化时,自动执行一些额外的逻辑。此时就可以通过一个属性装饰器来监视读写操纵。
  1. class Person {
  2.   @log
  3.   name: string;
  4.   constructor(name: string) {
  5.     this.name = name;
  6.   }
  7. }
  8. function log(target: object, name: string) {
  9.   console.log('----------log')
  10.   let value: any;
  11.   Object.defineProperty(target, name, {
  12.     set (newValue: any) {
  13.       console.log(`监视到${name}属性修改为${newValue}`);
  14.       value = newValue;
  15.     },
  16.     get () {
  17.       console.log(`监视到读取${name}属性`)
  18.       return value;
  19.     }
  20.   })
  21. }
  22. let person = new Person('张三');
  23. person.name='李四'
  24. console.log(person.name)
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表