马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
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用于声明常量,两者的区别是:变量在赋值后可以修改,而常量在赋值后便不能再修改。
- let a:number = 100
- const b:number = 200;
复制代码 类型推断
如果一个变量或常量的声明包罗了初始值,TS 便可以根据初始值举行类型推断,此时我们就可以不消显式的指定其类型,比方:
- let c = 60;
- console.log(typeof c); //number
复制代码 2.2. 常用数据类型
number类型
number表现数字,包括整数和浮点数,比方: 340、-23 、29.5、-13.4
- let a :number = 340
- let b :number = -23
- let c :number = 29.5
- let d :number = -13.4
复制代码 string类型
string表现字符串,比方: 你好、hello
- let a:string = '你好'
- let b:string = 'hello'
复制代码 boolean类型
boolean表现布尔值,可选值为:true、false
- let isOpen:boolean = true
- let isDone:boolean = false
复制代码 数组类型
数组类型定义由两部门组成,元素类型[],比方number[]表现数字数组,string[]表现字符串数组,数组类型的变量可由数组字面量——[item1,item2,item3]举行初始化。
- let a: number[] = []
- let b: string[] = ['你好', 'hello']
复制代码 对象类型
对象(object)类型的声明很简朴,只需声明属性名称和属性类型即可,比方{id:number,name:string},对象类型的变量可以通过对象字面量——{id:1,name:'zhangsan'}举行初始化。
- let person: { id: number, name: string } = { id: 1, name: 'zhangsan' };
复制代码
2.3. 函数
可选参数:可选参数通过参数名后的?举行标识,比方下面的gender?参数。
- function getPersonInfo(name: string, age: number, gender?: string) {
- if (!gender) {
- gender = '未知'
- }
- return `name:${name},age:${age},gender:${gender}`;
- }
- let p1 = getPersonInfo('zhagnsan', 10, '男')
- let p2 = getPersonInfo('lisi', 15);
- console.log(p1);
- console.log(p2);
复制代码 默认参数:可在函数的参数列表为参数指定默认值,如以下案例中的gender: string='未知'参数。
- function getPersonInfo(name: string, age: number, gender: string='未知') {
- return `name:${name},age:${age},gender:${gender}`;
- }
- let p1 = getPersonInfo('zhagnsan', 10, '男')
- let p2 = getPersonInfo('lisi', 15);
- console.log(p1);
- console.log(p2);
复制代码 联合类型:一个函数可能用于处理差别类型的值,这种环境可以使用联合类型,比方以下案例中的message: number | string
- function printNumberOrString(message: number | string) {
- console.log(message)
- }
- printNumberOrString('a')
- printNumberOrString(1)
复制代码 任意类型:若函数需要处理任意类型的值,则可以使用any类型,比方以下案例中的message: any
- function print(message:any) {
- console.log(message)
- }
- print('a')
- print(1)
- print(true)
复制代码 特别类型:若函数没有返回值,则可以使用void作为返回值类型,其含义为空。
- function test(): void {
- console.log('hello');
- }
复制代码 类型推断:函数的返回值类型可根据函数内容推断出来,因此可以省略不写。
- function test() {
- console.log('hello');
- }
- function sum(a: number, b: number) {
- console.log(a + b);
- }
复制代码 匿名函数:匿名函数的语法布局简便,特别适用于简朴且仅需一次性使用的场景。
- let numbers: number[] = [1, 2, 3, 4, 5]
- numbers.forEach(function (number) {
- console.log(number);
- })
复制代码 留意:匿名函数可以或许根据上下文推断出参数类型,因此参数类型可以省略。
箭头函数:匿名函数的语法还可以进一步的简化,只保留参数列表和函数体两个焦点部门,两者用=>符号连接。
- let numbers: number[] = [1, 2, 3, 4, 5]
- numbers.forEach((num) => { console.log(num) })
复制代码
2.4. 类(class)
概述:
类(class)是对象的蓝图或模板,它定义了对象的属性(数据)和行为(方法)。通过类可以创建多个具有相似布局和行为的对象。比方定义一个 Person类,其对象可以有张三、李四等等。
通过一个简朴案例,学习一下类的定义语法
示例代码:
- class Person {
- id: number;
- name: string;
- age: number = 18;
- constructor(id: number, name: string) {
- this.id = id;
- this.name = name;
- }
- introduce(): string {
- return `hello,I am ${this.name},and I am ${this.age} years old.`
- }
- }
复制代码
对象创建:创建对象的关键字为new,具体语法如下
- let person = new Person(1,'zhangsan,10);
复制代码 对象属性的访问
- console.log(person.name); //读
- person.name = 'lisi'; //写
- console.log(person.name);
复制代码 对象方法的调用:对象创建后,便可通过对象调用类中声明的方法,如下
- let intro = person.introduce();
- console.log(intro);
复制代码
静态成员
Typescript 中的类中可以包罗静态成员(静态属性和静态方法),静态成员从属于类自己,而不属于某个对象实例。静态成员通用用于定义一些常量,大概工具方法。
- 声明静态成员:定义静态成员需要使用static关键字。
- class Constants{
- static count:number=1;
- }
- class Utils{
- static toLowerCase(str:string){
- return str.toLowerCase();
- }
- }
- console.log(Constants.count);
- console.log(Utils.toLowerCase('Hello World'));
复制代码
- 使用静态成员:静态成员无需通过对象实例访问,直接通过类自己访问即可。
- console.log(Constants.count);
- console.log(Utils.toLowerCase('Hello World'));
复制代码 继承:
继承是面向对象编程中的重要机制,允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。子类可以直接使用父类的特性,并根据需要添加新的特性或覆盖现有的特性。这种机制赋予面向对象程序良好的扩展性。
下面通过一个例子演示继承的特性
- class Student extends Person {
- classNumber: string;
- constructor(id: number, name: string, age: number, classNumber: string) {
- super(id, name, age);
- this.classNumber = classNumber;
- }
- introduce(): string {
- return `hello,I am ${this.name},and I am ${this.age} years old, and I am a student`
- }
- }
- let student = new Student(1,'xiaoming',10,'三年二班');
- console.log(student.introduce());
复制代码
- 关键字:extends
- 新增属性:classNumber:string;
- 覆盖父类方法:introduce
- 构造器:子类构造器中需调用super(父类构造器)对继承的父类属性举行初始化。
权限修饰符
权限修饰符用于控制类成员(属性、方法等)的访问权限。它们有助于维护代码的封装性和安全性。TypeScript提供了三种访问修饰符,分别是 public、private 和 protected。
- public :公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的。
- private:私有的,只能在声明它的类中的被访问。
- protected:受掩护的,只能在声明它的类和其子类中被访问。
2.5. 接口(interface)
概述
接口(interface)是面向对象编程中的另一个重要概念。接口通常会作为类(class)的一种契约或规范,确保类实现了特定的行为或功能。通常环境下,接口中只会包罗属性和方法的声明,而不包罗具体的实现细节,具体的细节由实在现类完成。
接口定义:接口使用interface关键字定义,具体如下
- interface Person {
- id: number;
- name: string;
- age: number;
- job: string;
- introduce(): void;
- }
复制代码 接口实现
接口的实现需要用到implements关键字,实现类中,需要包罗接口属性的赋值逻辑,以及接口方法的实现逻辑。
- class Teacher implements Person {
- id: number;
- name: string;
- age: number;
- job: string = 'Teacher';
- constructor(id: number, name: string, age: number) {
- this.id = id;
- this.name = name;
- this.age = age;
- }
- introduce(): void {
- console.log(`Hello,I am ${this.name}`);
- }
- }
复制代码 作用
在传统的面向对象编程的场景中,接口主要用于计划和构造代码,使代码更加容易扩展和维护。下面举例说明。假如如今需要实现一个订单支付体系,按照面向对象编程的习惯,起首需要定义一个订单类(Order),如下
- class Order {
- total_amount: number;
- constructor(total_amount: number) {
- this.total_amount = total_amount;
- }
- pay() {
- console.log(`Pay:${this.total_amount}`);
- }
- }
复制代码 很容易预想到,订单需要未来可能需要支持多种支付方式,为了方便后期让代码支持新的支付方式,我们可以对代码举行如下改造。起首定义一个支付策略的接口,接口中声明了一个pay方法,用来规范实现类必须实现支付逻辑。
- interface PaymentStrategy {
- pay(amount: number): void;
- }
复制代码 然后在订单类中增长一个PaymentStrategy的属性,而且在订单类中的pay方法中调用PaymentStrategy的pay方法,如下
- class Order {
- total_amount: number;
- paymentStrategy: PaymentStrategy;
- constructor(total_amount: number, paymentStrategy: PaymentStrategy) {
- this.total_amount = total_amount;
- this.paymentStrategy = paymentStrategy;
- }
- pay() {
- this.paymentStrategy.pay(this.total_amount);
- }
- }
复制代码 如许改造完之后,就可以很容易的在不改变现有代码的环境下,支持新的支付方式了。
比如如今需要支持AliPay,那我们就可以创建AliPay这个类(class)并实现(implement)PaymentStrategy这个接口,如下
- class AliPay implements PaymentStrategy {
- pay(amount: number): void {
- console.log(`AliPay:${amount}`);
- }
- }
复制代码 如许一来,之后创建的订单就可以使用AliPay这个支付方式了。
- let order = new Order(1000,new AliPay());
- order.pay();
复制代码
TS 中的接口的特别性
TypeScript 中的接口是一个非常机动的概念,除了用作类的规范,让类去实现之外,也常用于直接形貌对象的类型,比方,现有一个方法的定义如下
- function getPersonInfo(person: { id: number, name: string, age: number }) {
- console.log(`[id:${person.id},name:${person.name},age:${person.age}]`);
- }
复制代码 可以看到该函数的参数类型为一个一般对象:{ id: number, name: string, age: number },此时就可以声明一个接口来形貌参数类型,如下,如许一来,函数定义就会更加简便明了。
- interface Person {
- id: number;
- name: string;
- age: number;
- }
- function getPersonInfo(person: Person) {
- console.log(`[id:${person.id},name:${person.name},age:${person.age}]`);
- }
复制代码 为使接口使用起来更加机动,TypeScript提出了可选属性的概念,语法如下
- interface Person {
- id: number;
- name: string;
- age?: number;
- }
复制代码 上述接口中的age字段就是一个可选属性,在声明该接口类型的对象时,便可根据实际环境选择性的包罗大概不包罗 age字段,如下
- getPersonInfo({ id: 1, name: 'zhangsan', age: 10 })
- getPersonInfo({ id: 2, name: 'lisi' })
复制代码 2.6. 枚举
概述
枚举(Enumeration)是一种编程语言中常见的数据类型,用于定义一组有限的定名常量,常用于表现特定的状态、类型或选项,比方方向(上、下、左、右)、季候(春、夏、秋、冬)等。
- enum Direction {
- UP,
- BOTTOM,
- LEFT,
- RIGHT
- }
- function move(direction: Direction) {
- switch (direction) {
- case Direction.UP:
- console.log('向上移动');
- break;
- case Direction.BOTTOM:
- console.log('向下移动');
- break;
- case Direction.LEFT:
- console.log('向左移动');
- break;
- case Direction.RIGHT:
- console.log('向右移动');
- break;
- default:
- console.log('原地不动')
- break;
- }
- }
- move(Direction.UP);
复制代码 枚举的使用记着两个原则
像访问对象属性一样访问枚举值,比方Direction.UP
枚举值的类型为enum的名称,比方Direction.UP和Direction. BOTTOM等值的类型都是Direction
枚举原理
默认环境下,每个属性的值都是数字,而且从 0 开始递增,比方上述案例中的Direction枚举中,Direction.UP的值为0,Direction.BOTTOM的值为1,依次类推,具体如下
- console.log(Direction.UP) //0
- console.log(Direction.BOTTOM) //1
- console.log(Direction.LEFT) //2
- console.log(Direction.RIGHT) //3
复制代码 除了使用默认的数字作为属性的值,我们还能手动为每个属性赋值,比方
- enum Direction {
- UP = 1,
- BOTTOM = 2,
- LEFT = 3,
- RIGHT = 4
- }
- console.log(Direction.UP) //1
- console.log(Direction.BOTTOM) //2
- console.log(Direction.LEFT) //3
- console.log(Direction.RIGHT) //4
复制代码 再比方
- enum Direction {
- UP = 'up',
- BOTTOM = 'bottom',
- LEFT = 'left',
- RIGHT = 'right'
- }
- console.log(Direction.UP) //up
- console.log(Direction.BOTTOM) //bottom
- console.log(Direction.LEFT) //left
- console.log(Direction.RIGHT) //right
复制代码 留意:
多数环境下,我们只是用枚举来表现几种差别的状态,以便在差别的状态下采取差别的举措,这时一般无需关注每个属性具体的值。
2.7. 模块化
概述
模块化是将复杂的程序拆解为多个独立的文件单位,每个文件被称为一个模块。在 TypeScript 中,默认环境下,每个模块都拥有自己的作用域,这意味着在一个模块中声明的任何内容(如变量、函数、类等)在该模块外部是不可见的,除非明确导出。同时,为了在一个模块中使用其他模块的内容,必须先将这些内容显式导入到当前模块中。
导出:导出须使用export关键字,语法如下
- export function hello() {
- console.log('hello module A');
- }
- export const str = 'hello world';
- const num = 1;
复制代码 导入:导入须使用import关键字,语法如下
- import { hello, str } from './moduleA';
- hello();
- console.log(str);
复制代码 避免定名冲突
若多个模块中具有定名雷同的变量、函数等内容,将这些内容导入到同一模块下就会出现定名冲突。比方,在上述案例的底子上,又增长了一个 moduleC,内容如下
- export function hello() {
- console.log('hello module C');
- }
- export const str = 'module C';
复制代码 moduleB 同时引入 moduleA 和 moduleC 的内容,如下,显然就会出定名冲突
- import { hello, str } from "./moduleA";
- import { hello, str } from "./moduleC";
- hello() //?
- console.log(str); //?
复制代码 有多种方式可以用来办理定名冲突,下面逐一介绍
- import { hello as helloFromA, str as strFromA } from "./moduleA";
- import { hello as helloFromC, str as strFromC } from "./moduleC";
- helloFromA();
- console.log(strFromA);
- helloFromC();
- console.log(strFromC);
复制代码
上述导入重定名的方式可以或许很好的办理定名冲突的问题,但是当冲突内容较多时,这种写法会比较冗长。除了导入重定名外,还可以将某个模块的内容同一导入到一个模块对象上,如许就能简便有效的办理定名冲突的问题了,具体语法如下
- import * as A from "./moduleA";
- import * as C from "./moduleC";
- A.hello();
- console.log(A.str);
- C.hello();
- console.log(C.str);
复制代码
除了上述导入导出的语法之外,还有一种语法,叫做默认导入导出,这种语法相对简便一些。
- 默认导出:默认导出允许一个模块指定一个(最多一个)默认的导出项,语法如下
- export default function hello(){
- console.log('moduleA');
- }
复制代码 默认导出支持匿名导出项,语法如下
- export default function () {
- console.log('moduleB');
- }
复制代码
由于每个模块最多有一个默认导出,因此默认导入无需指定导入项的原名称,而且无需使用{}。
- import helloFromA from "./moduleA";
- import helloFromB from "./moduleB";
复制代码 上述语法相当于以下语法的简写
- import { default as helloFromA } from "./moduleA";
- import { default as helloFromB } from "./moduleB";
复制代码 2.8. 装饰器
概述
在TypeScript中,装饰器是一种特别类型的声明,可以被附加到类,属性,方法上。装饰器的焦点头脑是在尽量不改变原始类的定义的环境下,为类添加新的特性。
装饰器使用@Expression的形式。其中,Expression为一个函数,这个函数负责定义为类添加的新特性,其会在运行时被调用。
ArkTS 提供了多种装饰器,同时在鸿蒙应用的开发中我们也会大量使用这些装饰器,因此学习装饰器语法,对于明白鸿蒙应用的执行原理有很大资助。
装饰器的分类
按照声明位置的差别,装饰器可以分为类装饰器、方法装饰器和属性装饰器等,差别装饰器可用于实现差别的功能。
类装饰器可以拦截并修改类的构造函数,这使得我们可以在实例化对象时增长一些额外的逻辑。
- @ClassDecorator
- class A {
- }
- /**
- * 装饰器函数
- * 在第一次引用A类时执行
- * @param target 被装饰的类
- */
- function ClassDecorator (target) {
- // 给目标类添加静态属性
- target.xxx = 'abc'
- }
- console.log((A as any).xxx) // abc
复制代码
使用方法装饰器可以拦截并修改所装饰的方法,这使得我们可以在调用该方法之前或之后执行一些额外的逻辑。
- class A {
- @MethodDecorator
- hello(){
- console.log('hello()');
- }
- }
- /**
- * 方法装饰器
- * 在第一次调用方法前执行
- * @param target 方法所属类的原型对象
- * @param name 方法名
- * @param descriptor 方法属性对应的描述符对象
- */
- function MethodDecorator (target: object, name: string, descriptor: PropertyDescriptor) {
- console.log(`${name}方法将要第一次调用了`, target, name, descriptor);
- }
- const a = new A()
- a.hello()
复制代码
属性装饰器可以拦截对属性的读写操纵,并在这些操纵之前或之后执行一些额外的逻辑。
- class A {
- @PropertyDecorator
- name: string;
- }
- /**
- * 属性装饰器
- * 在第一次创建对象内部初始化属性时执行
- * @param target 属性所属类的原型对象
- * @param name 属性名
- */
- function PropertyDecorator (target: object, name: string) {
- console.log(`将要第一次操作${name}属性`, target, name);
- }
- const a = new A() // 内部会将name属性添加给a对象,自动调用PropertyDecorator
复制代码 简朴案例
下面通过一个简朴的案例,演示装饰器的作用,比方如今需要监听某一个属性的变化,当其发生变化时,自动执行一些额外的逻辑。此时就可以通过一个属性装饰器来监视读写操纵。
- class Person {
- @log
- name: string;
- constructor(name: string) {
- this.name = name;
- }
- }
- function log(target: object, name: string) {
- console.log('----------log')
- let value: any;
- Object.defineProperty(target, name, {
- set (newValue: any) {
- console.log(`监视到${name}属性修改为${newValue}`);
- value = newValue;
- },
- get () {
- console.log(`监视到读取${name}属性`)
- return value;
- }
- })
- }
- let person = new Person('张三');
- person.name='李四'
- console.log(person.name)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |