大学网站建设招标,深圳市做门窗网站有哪些推广,郑州网站如何制作,wordpress 最大上传一、背景
HarmonyOS 应用的主要开发语言是 ArkTS#xff0c;它由 TypeScript#xff08;简称TS#xff09;扩展而来#xff0c;在继承TypeScript语法的基础上进行了一系列优化#xff0c;使开发者能够以更简洁、更自然的方式开发应用。值得注意的是#xff0c;TypeScrip…一、背景
HarmonyOS 应用的主要开发语言是 ArkTS它由 TypeScript简称TS扩展而来在继承TypeScript语法的基础上进行了一系列优化使开发者能够以更简洁、更自然的方式开发应用。值得注意的是TypeScript 本身也是由另一门语言 JavaScript 扩展而来。因此三者的关系如下图所示 二、TypeScript
2.1、运行环境
2.1.1、线上Playground
TypeScript提供了一个线上的 Playground 供练习使用地址为TypeScript: 演练场 - 一个用于 TypeScript 和 JavaScript 的在线编辑器。 2.1.2、本地运行环境
2.1.2.1、采用的是VSCode 编辑器
2.1.2.2、前提条件
1、安装插件Code Runner它提供了简便的代码执行功能支持多种编程语言使开发者能够快速运行和调试代码片段。 2、安装Node.js并配置Path环境变量
说明我已经安装了Node.js便不重复安装了
为了方便在终端执行Node.js相关的命令我们需要将Node.js的安装目录加入到Path环境变量下
步骤1首先在DevEco Studio的设置界面查看Node.js的安装目录 步骤2然后打开环境变量配置面板按下 WinR 唤起运行窗口之后运行命令 sysdm.cpl 步骤3点击高级选项卡并点击环境变量 步骤4在系统变量中选中 Path 并点击编辑 步骤5点击新建并填入Node.js的安装目录完成后点击确定 3、安装ts-node
这是一个 TypeScript 的运行环境它允许我们直接运行 TypeScript 代码。ts-node的安装和运行依赖于Node.js环境已经安装了Node.js
npm install -g ts-node
在终端中输入node -v 和ts-node -v后出现各自版本说明这两个已经安装成功了如下 注完成后需要重新启动VSCode另其重新加载环境变量和相关依赖。
2.1.2.3、编写程序并运行
首先在合适的位置创建一个工程目录例如C:\Users\......\hello-ts然后使用VSCode打开目录创建ts文件并编写Typescript代码运行
问题运行ts时出现以下错误百度后发现是由于 ts-node 版本升级导致的兼容性问题 解决需要在项目中安装 types/node
npm install --save-dev types/node
效果 安装 types/node 后再运行就能够正常打印日志了 2.2、声明
2.2.1、变量声明 2.2.2、常量声明 let用于声明变量而const用于声明常量两者的区别是变量在赋值后可以修改而常量在赋值后便不能再修改。
const b:number 200;
2.2.3、类型推断
如果一个变量或常量的声明包含了初始值TS 便可以根据初始值进行类型推断此时我们就可以不显式指定其类型例如
let c 60;
console.log(typeof c); //number
2.3、常用数据类型
2.3.1、number
number表示数字包括整数和浮点数例如 100、-33 、2.5、-3.9
let a :number 100
let b :number -33
let c :number 2.5
let d :number -3.9
2.3.2、string
string表示字符串例如 你好、hello
let a:string 你好
let b:string hello 2.3.3、boolean
boolean表示布尔值可选值为true、false
let isOpen:boolean true
let isDone:boolean false 2.3.4、数组
数组类型定义由两部分组成元素类型[]例如number[]表示数字数组string[]表示字符串数组数组类型的变量可由数组字面量——[item1,item2,item3]进行初始化。
let a: number[] []
let b: string[] [你好, hello]
2.3.5、对象
在TS中对象object是一种一系列由属性名称和属性值组成的数据结构例如姓名:张三, 年龄:10, 性别:男。对象类型的声明需要包含所有属性的名称及类型例如{name: string, age: number, gender: string}对象类型的变量可以通过对象字面量——{name:张三, age:10, gender:男}进行初始化。
let person: {name:string, age:number, gender:string} {name:张三, age:10, gender:男};
2.4、函数
2.4.1、函数声明语法
声明函数的基础语法如下 2.4.2、参数
2.4.2.1、特殊语法
①可选参数
可选参数通过参数名后的?进行标识如以下案例中的gender?参数。
function getPersonInfo(name: string, age: number, gender?: string): string {if (gender undefined) {gender 未知}return name:${name},age:${age},gender:${gender};
}let p1 getPersonInfo(zhagnsan, 10, 男)
let p2 getPersonInfo(lisi, 15);
console.log(p1);
console.log(p2);
注调用函数时未传递可选参数则该参数的值为undefined。
②默认参数
可在函数的参数列表为参数指定默认值如以下案例中的gender: string未知参数。
function getPersonInfo(name: string, age: number, gender: string未知): string {return name:${name},age:${age},gender:${gender};
}let p1 getPersonInfo(zhagnsan, 10, 男)
let p2 getPersonInfo(lisi, 15);
console.log(p1);
console.log(p2);
2.4.2.2、 特殊类型
①联合类型
一个函数可能用于处理不同类型的值这种情况可以使用联合类型例如以下案例中的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)
2.4.3、 返回值
2.4.3.1、特殊类型
若函数没有返回值则可以使用void作为返回值类型其含义为空。
function test(): void {console.log(hello);
}
2.4.3.2、类型推断
函数的返回值类型可根据函数内容推断出来因此可以省略不写。
function test() {console.log(hello);
}function sum(a: number, b: number) {return a b;
}
2.4.4、函数声明特殊语法
①匿名函数
匿名函数的语法结构简洁特别适用于简单且仅需一次性使用的场景。
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.5、类
2.5.1、类介绍
类class是面向对象编程语言中的一个重要概念。
面向对象编程Object-Oriented Programming简称OOP是一种编程范式其核心理念在于将程序中的数据与操作数据的方法有机地组织成对象从而使程序结构更加模块化和易于理解。通过对象之间的协同合作实现更为复杂的程序功能。
类class是对象的蓝图或模板它定义了对象的属性数据和行为方法。通过类可以创建多个具有相似结构和行为的对象。例如定义一个 Person类其对象可以有张三、李四等等。
2.5.2、语法说明
2.5.2.1、类的定义 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}
}
2.5.2.2、对象创建
①语法
创建对象的关键字为new具体语法如下
let person new Person(1,zhangsan);
②对象属性的访问
console.log(person.name); //读person.name lisi; //写console.log(person.name);
③对象方法的调用
对象创建后便可通过对象调用类中声明的方法如下
let intro person.introduce();
console.log(intro);
2.5.2.3、静态成员
Typescript 中的类中可以包含静态成员静态属性和静态方法静态成员隶属于类本身而不属于某个对象实例。静态成员通用用于定义一些常量或者工具方法。
①声明静态成员
定义静态成员需要使用static关键字。
class Constants{static count:number1;
}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));
2.5.3、继承
继承是面向对象编程中的重要机制允许一个类子类或派生类继承另一个类父类或基类的属性和方法。子类可以直接使用父类的特性并根据需要添加新的特性或覆盖现有的特性。这种机制赋予面向对象程序良好的扩展性。
class Student extends Person {classNumber: string;constructor(id: number, name: string, classNumber: string) {super(id, name);this.classNumber classNumber;}introduce(): string {return super.introduce(), and I am a student;}
}let student new Student(1,xiaoming,三年二班);
console.log(student.introduce()); 注意 类的继承需要使用关键字extends子类构造器中需使用super()调用父类构造器对继承自父类的属性进行初始化。在子类中可以使用this关键字访问继承自父类的属性和方法。在子类中可以使用super关键字访问父类定义的方法。 2.5.4、访问修饰符
访问修饰符Access Modifiers用于控制类成员属性、方法等的可访问性。TypeScript提供了三种访问修饰符分别是private、protected和public。
class Person {private id: number;protected name: string;public age: number;constructor(id: number, name: string, age: number) {this.id id;this.name name;this.age age;}
}class Student extends Person {} 说明 private 修饰的属性或方法是私有的只能在声明它的类中的被访问。protected 修饰的属性或方法是受保护的只能在声明它的类和其子类中被访问。public 修饰的属性或方法是公有的可以在任何地方被访问到默认所有的属性和方法都是 public 的。 2.6、接口
2.6.1、接口介绍
接口interface是面向对象编程中的另一个重要概念。接口通常会作为一种契约或规范让类class去遵守确保类实现某些特定的行为或功能。
2.6.2、语法说明
①接口定义
接口使用interface关键字定义通常情况下接口中只会包含属性和方法的声明而不包含具体的实现细节具体的细节由其实现类完成。
interface Person {id: number;name: string;age: number;introduce(): void;
}
②接口实现
接口的实现需要用到implements关键字实现类中需要包含接口属性的赋值逻辑以及接口方法的实现逻辑。
class Student implements Person {id: number;name: string;age: number;constructor(id: number, name: string, age: number) {this.id id;this.name name;this.age age;}introduce(): void {console.log(Hello,I am a student);}
}
2.6.3、多态
多态是面相对象编程中的一个重要概念它可以使同一类型的对象具有不同的行为。下面我们通过一个具体的案例来体会多态这一概念
首先再创建一个Person接口的实现类Teacher如下
class Teacher implements Person {id: number;name: string;age: number;constructor(id: number, name: string, age: number) {this.id id;this.name name;this.age age;}introduce(): void {console.log(Hello,I am a teacher);}
}
然后分别创建一个Student对象和一个Teacher对象注意两个对象的类型均可以设置Person如下
let p1: Person new Student(1, zhangsan, 17);
let p2: Person new Teacher(2, lisi, 35);
最后分别调用p1和p2的introduce()方法你会发现同样是Person类型的两个对象调用同一个introduce()方法时表现出了不同的行为这就是多态。
p1.introduce();//Hello,I am a student
p2.introduce();//Hello,I am a teacher
2.6.4、接口的作用
在传统的面向对象编程的场景中接口主要用于设计和组织代码使代码更加容易扩展和维护。
假如现在需要实现一个订单支付系统按照面向对象编程的习惯首先需要定义一个订单类Order如下
class Order {totalAmount: number;constructor(totalAmount: number) {this.totalAmount totalAmount;}pay() {console.log(AliPay:${this.totalAmount});}
}
很容易预想到这个系统将来可能需要支持其他的支付方式为了方便代码支持新的支付方式我们可以对代码进行如下改造。
首先定义一个支付策略的接口接口中声明一个pay方法用来规范实现类必须实现支付逻辑。
interface PaymentStrategy {pay(amount: number): void;
}
然后在订单类中增加一个PaymentStrategy的属性并且在订单类中的pay方法中调用PaymentStrategy的pay方法如下
class Order {totalAmount: number;paymentStrategy: PaymentStrategy;constructor(totalAmount: number, paymentStrategy: PaymentStrategy) {this.totalAmount totalAmount;this.paymentStrategy paymentStrategy;}pay() {this.paymentStrategy.pay(this.totalAmount);}
}
这样改造完之后就可以很容易的在不改变现有代码的情况下支持新的支付方式了。
比如现在需要支持AliPay那我们就可以创建AliPay这个类class并实现implementPaymentStrategy这个接口如下
class AliPay implements PaymentStrategy {pay(amount: number): void {console.log(AliPay:${amount});}
}
这样一来之后创建的订单就可以使用AliPay这个支付方式了。
let order new Order(1000,new AliPay());
order.pay();
2.6.5、TS中接口的特殊性
TypeScript 中的接口是一个非常灵活的概念除了用作类的规范之外也常用于直接描述对象的类型例如现有一个变量的定义如下
let person: {name:string, age:number, gender:string} {name:张三, age:10, gender:男};
可以看到变量的值为一个一般对象变量的类型为{name:string, age:number, gender:string}此时就可以声明一个接口来描述该对象的类型如下
interface Person {name: string;age: number;gender: string;
}let person: Person {name:张三, age:10, gender:男};
2.7、枚举
2.7.1、枚举介绍
枚举Enumeration是编程语言中常见的一种数据类型其主要功能是定义一组有限的选项例如方向上、下、左、右或季节春、夏、秋、冬等概念都可以使用枚举类型定义。
2.7.2、语法说明
①枚举定义
枚举的定义需使用enum关键字如下
enum Season {SPRING,SUMMER,AUTUMN,WINTER
}
②枚举使用 枚举的使用记住两个原则即可 枚举值的访问 像访问对象属性一样访问枚举值例如Season.SPRING 枚举值的类型 枚举值的类型为enum的名称例如Season.SPRING和Season.SUMMER等值的类型都是Season let spring:Season Season.SPRING;
③使用场景
现需要编写一个函数move其功能是根据输入的方向上、下、左、右进行移动此时就可以先使用枚举定义好所有可能的输入选项如下
enum Direction {UP,BOTTOM,LEFT,RIGHT
}
move函数的实现如下
function move(direction: Direction) {if(directionDirection.UP){console.log(向上移动);}else if(directionDirection.BOTTOM){console.log(向下移动);}else if(directionDirection.LEFT){console.log(向左移动);}else{console.log(向右移动);}
}move(Direction.UP);
2.7.3、赋值
在TypeScript 中枚举实际上是一个对象而每个枚举值都是该对象的一个属性并且每个属性都有具体的值属性值只支持两种类型——数字或字符串。
默认情况下每个属性的值都是数字并且从 0 开始递增例如上述案例中的Direction枚举中Direction.UP的值为0Direction.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
通过为枚举属性赋值可以赋予枚举属性一些更有意义的信息例如以下枚举
enum Color {Red 0xFF0000,Green 0x00FF00,Blue 0x0000FF
}enum FontSize {Small 12,Medium 16,Large 20,ExtraLarge 24
}
2.8、模块化
2.8.1、模块化介绍
模块化是指将复杂的程序拆解为多个独立的文件单元每个文件被称为一个模块。在 TypeScript 中默认情况下每个模块都拥有自己的作用域这意味着在一个模块中声明的任何内容如变量、函数、类等在该模块外部是不可见的。为了在一个模块中使用其他模块的内容必须对这些内容进行导入、导出。
2.8.2、语法说明
①导出
导出须使用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); 2.8.3、避免命名冲突
若多个模块中具有命名相同的变量、函数等内容将这些内容导入到同一模块下就会出现命名冲突。例如在上述案例的基础上又增加了一个 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);
2.8.4、默认导入导出
①默认导出
默认导出允许一个模块指定一个最多一个默认的导出项语法如下
export default function hello(){console.log(moduleA);
}
②默认导入
由于每个模块最多有一个默认导出因此默认导入无需关注导入项的原始名称并且无需使用{}。
import helloFromA from ./moduleA;
由于默认导入时无需关注导入项的名称所以默认导出支持匿名内容比如匿名函数语法如下
export default function () {console.log(moduleB);
} 最后