类Class
类声明(class )引入一个新类型,并定义其字段、方法和构造函数(constructor )。
类中的属性与方法声明不需要let或者function定义。
例如:
class Person { //类名建议首字母大写
name: string = ''//无构造函数时需要给初始值;或者写成可选值name?: string
surname: string = ''
constructor (n: string, sn: string) {//构造函数
this.name = n;
this.surname = sn;
}
fullName(): string {
return this.name + ' ' + this.surname;
}
}
定义类后,可以使用关键字new创建实例(构造函数);
或者,可以使用对象字面量创建实例。
字段初始化——给初始值或者可选值
为了减少运行时的错误和获得更好的执行性能,
ArkTS要求所有字段在声明时或者构造函数中显式初始化
。这和标准TS中的strictPropertyInitialization模式一样。
如果字段未被初始化,在get函数中
getName(): string {
// 开发者使用"string"作为返回类型,这隐藏了name可能为"undefined"的事实。
// 更合适的做法是将返回类型标注为"string | undefined",以告诉开发者这个API所有可能的返回值。
return this.name;
}
// 假设代码中没有对name赋值,例如没有调用"jack.setName(‘Jack’)"
jack.getName().length; // 运行时异常:name is undefined
==重要:==如果name的值可以是undefined,应该这样写代码:
class Person {
name?: string // 可能为`undefined`---------可选参数声明
setName(n:string): void {
this.name = n;
}
// 编译时错误:name可以是"undefined",所以将这个API的返回值类型标记为string
getNameWrong(): string {
return this.name;
}
getName(): string | undefined { // 返回类型匹配name的类型
return this.name;
}
}
let jack = new Person();
// 假设代码中没有对name赋值,例如没有调用"jack.setName('Jack')"
// 编译时错误:编译器认为下一行代码有可能会访问undefined的属性,报错
jack.getName().length; // 编译失败,因为可选值不存在。
jack.getName()?.length; // 编译成功,没有运行时错误
调用get函数后面加?
与不加的区别?
** getNameWrong()**该函数的作用?
构造函数——不写死初始值,需提供constructor
类声明可以包含用于初始化对象状态的构造函数。
constructor ([parameters]) {
// ...
}
如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数。在这种情况下,默认构造函数使用字段类型的默认值来初始化实例中的字段。
拓:如果参数比较复杂,可以定义一个参数接口,一整个传给constructor。
getter和setter
setter和getter可用于提供对对象属性的受控访问。
在以下示例中,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值会抛出错误
实例字段和静态字段(属性/方法)
字段是直接在类中声明的某种类型的变量。
类可以具有实例字段或者静态字段(static声明静态字段
)。
使用关键字static将字段声明为静态。静态字段属于类本身(可以使用类名直接调用),类的所有实例共享一个静态字段。
静态属性和静态方法通过类名直接调用。静态属性不设置值的情况下,默认是undefined。
实例方法和静态方法
静态方法属于类本身,只能访问静态字段。
而实例方法既可以访问静态字段,也可以访问实例字段,包括类的私有字段。
实例方法必须通过类的实例调用。
静态方法定义了类作为一个整体的公共行为。可通过类名调用。
方法定义:
类的继承 extends
一个类可以继承另一个类(称为基类),并使用以下语法实现多个接口:
class 子类 [extends 基类] [implements 接口] {
// ...
}
基类也称为“父类”或“超类”。继承类也称为“派生类”或“子类”。
(继承一个类,实现多接口)
继承类继承基类的字段和方法,但不继承构造函数。
继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。
包含implements子句的类必须实现列出的接口中定义的所有方法
,但使用默认实现定义的方法除外。(默认实现的定义方法是什么?)
父类访问 super
关键字super可用于访问父类的实例字段、实例方法和构造函数。在实现子类功能时,可以通过该关键字从父类中获取所需接口:
class FilledRectangle extends RectangleSize {
color = ''
constructor (h: number, w: number, c: string) {
super(h, w); // 父类构造函数的调用
this.color = c;
}
draw() {
super.draw(); // 父类方法的调用
// super.height -可在此处使用
/* 填充矩形 */
}
}
方法重写
子类可以重写其父类中定义的方法的实现。重写的方法必须具有相同的方法名
、与原始方法相同的参数类型
和相同或派生的返回类型
。
方法重载签名
通过重载签名,指定方法的不同调用。
具体方法为,为同一个方法写入多个同名但签名不同的方法头,方法实现紧随其后。
(这里的签名不同,展示的是参数列表的个数/参数类型各不相同)
派生类的构造函数
构造函数函数体的第一条语句
可以使用关键字super来显式调用直接父类的构造函数。
class Square extends RectangleSize {
constructor(side: number) {
super(side, side);
}
}
构造函数重载签名
我们可以通过编写重载签名,指定构造函数的不同调用方式。具体方法为,为同一个构造函数写入多个同名但签名不同的构造函数头,构造函数实现紧随其后。
instanceof 检测某个对象是否是某个类的实例化
实例对象 instanceof 类名
typeof 变量名 # 用于判断简单类型
可见性修饰符
类的方法和属性都可以使用可见性修饰符。
可见性修饰符包括:private、protected和public。默认可见性为public。
private:仅在声明类内访问
protected:声明类和派生类(子类)
public:可访问该类的地方都可见
readonly:只读的,不可修改。无访问限制。
接口
任何一个类的实例只要实现了特定接口,就可以通过该接口实现多态
。
接口通常包含属性和方法的声明,示例:
interface Style {
color: string // 属性
}
interface AreaSize {
calculateAreaSize(): number // 方法的声明
someMethod(): void; // 方法的声明
}
接口属性
接口属性可以是字段、getter、setter或getter和setter组合的形式。
属性字段只是getter/setter对的便捷写法。以下表达方式是等价的:
interface Style {
color: string
}
=============================
interface Style {
get color(): string
set color(x: string)
}
实现接口的类也可以使用以下两种方式:
interface Style {
color: string
}
//第一种
class StyledRectangle implements Style {
color: string = ''
}
//第二种
class StyledRectangle implements Style {
private _color: string = ''
get color(): string { return this._color; }
set color(x: string) { this._color = x; }
}
接口继承
接口可以继承其他接口。继承接口包含被继承接口的所有属性和方法,还可以添加自己的属性和方法。
接口实现
interface IAnimal{
name:string,
age:number,
jump:()=>void
}
class Cat implements IAnimal{
name: string
age: number
//alt+insert自动生成
constructor(name: string, age: number) {
this.name = name
this.age = age
}
jump(){
}
}
对象字面量
==对象字面量是一个表达式,可用于创建类实例并提供一些初始值。==它在某些情况下更方便,可以用来代替new表达式。
Record类型的对象字面量
泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。