【笔记】TS的面向对象

前言

TS的面向对象

定义类

  • 类名通常大写
1
2
3
class 类名 {
...
}

创建对象

1
const 对象名 = new 类名();

属性

定义实例属性

1
2
3
class 类名 {
属性名: 类型 = 属性值;
}

通过对象访问实例属性

1
对象名.属性名 = 属性值;

定义类属性(静态属性)

  • 通过statis关键字定义类属性
1
2
3
class 类名 {
static 属性名: 类型;
}

通过类名访问类属性

1
类名.属性名 = 属性值;

定义只读属性

  • 通过readonly关键字定义只读属性
  • 只读属性不能
1
2
3
class 类名 {
readonly 属性名: 类型 = 属性值;
}

定义静态只读属性

1
2
3
class 类名 {
ststic readonly 属性名: 类型 = 属性值;
}

方法

定义实例方法

1
2
3
4
5
class 类名 {
方法名() {
...
}
}

通过对象调用实例方法

1
对象名.方法名();

定义类方法

  • 通过static关键字定义类方法
1
2
3
4
5
class 类名 {
static 方法名() {
...
}
}

通过类名调用类方法

1
类名.方法名();

构造方法

  • 通过constructor作为方法名定义构造方法
  • this表示当前的实例
1
2
3
4
5
6
7
8
class 类名 {

属性名: 类型;

constructor(属性名: 类型) {
this.属性名 = 属性名;
}
}

通过构造方法创建对象

1
const 对象名 = new 类名(属性值);

继承

子类继承父类

  • 通过extends关键字实现类的继承
1
2
3
4
5
6
7
class Father {
...
}

class Son extends Father {
...
}

方法的重写

  • 如果子类定义了与父类同名的方法,那么子类的这个方法将被重写
1
2
3
4
5
6
7
8
9
10
11
class Father {
同名的方法() {
...
}
}

class Son extends Father {
同名的方法() {
...
}
}

获取父类的实例

  • 通过super关键字获取父类的实例
    • 通过super()调用父类的构造方法
      • 如果子类定义了构造方法,一定要在子类的构造方法中调用一次父类的构造方法
    • 通过super.方法名调用父类的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Father {

属性名: 数据类型;

constructor(属性名: 数据类型) {
this.属性名 = 属性名;
}

父类的方法() {
...
}
}

class Son extends Father {

属性名: 数据类型;

constructor(属性名: 数据类型) {
super(属性名);
}

子类的方法() {
super.父类的方法()
}
}

抽象类

定义抽象类

  • 通过abstract关键字定义抽象类,抽象类不能创建对象,主要用途是作为父类被继承
1
2
3
4
5
6
7
abstract class Father {
...
}

class Son extends Father {
...
}

定义抽象方法

  • 在抽象类中可以通过abstract关键字定义抽象方法,抽象方法没有方法体
  • 子类继承了包含抽象方法的抽象类,必须重写抽象方法
1
2
3
4
5
6
7
abstract class Father {
abstract 抽象方法名(形参列表): 返回值类型;
}

class Son extends Father {
...
}

接口

定义接口

  • 通过interface关键字定义接口
  • 接口用来定义类的结构,用来定义类中应该包含哪些属性和方法
  • 接口中的方法只能是抽象方法
1
2
3
4
5
6
7
interface 接口名 {

属性名: 数据类型;

方法名(): void;

}

实现接口

  • 通过implements关键字实现接口
  • 实现接口的子类必须重写接口中定义的所有属性和方法
1
2
3
4
5
6
7
8
9
10
11
12
class 类名 implements 接口名 {

属性名: 数据类型;

constructor(属性名: 数据类型) {
this.属性名 = 属性名;
}

方法名() {
...
}
}

封装

  • 通过权限修饰符限定属性的作用域

public:公共的,缺省值,可以在任意一次修改
private:私有的,只能在类内部使用
protected:受保护的,只能在当前类及其子类内部使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class 类名 {

private _属性名: 数据类型;

constructor(属性名: 数据类型) {
this._属性名 = 属性名;
}

get属性名(): 数据类型 {
return this._属性名;
}

set属性名(属性名: 数据类型) {
this._属性名 = 属性名;
}
}

Getter方法的简写

1
2
3
get 属性名() {
return this._属性名;
}

直接通过.就能触发Getter方法

1
对象名.属性名;

Setter方法简写

1
2
3
set 属性名(属性名: 数据类型) {
this._属性名 = 属性名;
}

直接通过.就能触发Setter方法

1
对象名.属性名 = 属性值;

类中属性的简写

  • 在定义类时无需定义属性,直接在构造方法的形参列表中通过添加权限修饰符的方式定义类的属性
1
2
3
4
5
6
7
class 类名 {

constructor(public 属性名: 数据类型) {
this.属性名 = 属性名;
}

}

泛型

定义函数时定义泛型

  • 在定义函数时,如果遇到类型不明确的情况,可以使用泛型
1
2
3
function 方法名<T>(形参: T): T {
return 形参
}

定义多个泛型

1
2
3
function 方法名<T, K>(形参: T): T {
return 形参
}

调用函数时指定泛型

1
方法名<实际数据类型>(实参);

指定多个泛型

1
方法名<实际数据类型, 实际数据类型>(实参);

调用函数时不指定泛型

  • 实际调用时,TypeScript会自动推断泛型类型
1
方法名(实参);

继承接口的泛型

1
2
3
4
5
6
7
interface 接口名 {
属性名: 数据类型;
}

function 方法名<T extends 接口名>(形参: T): T {
return 形参
}

调用包含实现接口的泛型的函数

  • 在调用包含实现接口的泛型的函数,传递的参数应当时实现了接口的类实例
1
2
3
4
5
6
class 类名 interface 接口名 {
属性名: 数据类型;
}

const 对象名 = new 类名();
方法名<接口名>(对象名);

完成

参考文献

哔哩哔哩——尚硅谷