“不畏惧,不将就,未来的日子好好努力”——大家好!我是小芝麻😄

类(Class)定义了一件事物的抽象特点,包含它的属性和方法

1、定义类

TypeScript 中,我们也是通过 Class 关键字来定义一个类, 使用 constructor 定义构造函数。

构造函数: constructor

  • 主要用于初始化类的成员变量属性
  • 类的对象创建时自动调用执行
  • 没有返回值
 1class Animal {
 2    public name: string;
 3    constructor(name: string) {
 4        this.name = name;
 5    }
 6    sayHi(): string {
 7        return `My name is ${this.name}`;
 8    }
 9}

2、类的继承

使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法。

  • 子类继承父类后子类的实例就拥有了父类中的属性和方法,可以增强代码的可复用性
  • 将子类共用的方法抽象出来放在父类中,自己特殊逻辑放在子类中重写父类的逻辑
  • super 可以调用父类上的方法和属性: (相当于ES5的:在静态方法和构造函数中指向父类; 在普通函数中指向父类的prototype;)
 1class Animal {
 2    public name: string;
 3    constructor(name: string) {
 4        this.name = name;
 5    }
 6    sayHi(): string {
 7        return `My name is ${this.name}`;
 8    }
 9}
10
11class Cat extends Animal {
12  constructor(name) {
13    super(name); 
14    console.log(this.name);
15  }
16  sayHi(): string { 
17    return 'Meow, ' + super.sayHi(); 
18  }
19}
20
21let c = new Cat('Tom'); 
22console.log(c.sayHi()); 

2.1 重写(override) VS 重载(overload)

  • 重写是指子类重写继承自父类的方法
  • 重载是指为同一个函数提供多个类型定义

2.2 继承 VS 多态

  • 继承(inheritance)子类继承父类,子类除了拥有父类的所有特性外,还有一些具体的特性
  • 多态(Polymorphism)由继承而产生了相关的不同的类,对同一个方法可以有不同的行为

3、类的修饰符

TypeScript 中有三类访问修饰符,分别是: publicprivateprotected不写默认为 public

  • public :自己、自己的子类 和其他类都可以访问 (默认值)
  • protected 受保护的 自己和自己的子类能访问, 其他类不能访问
  • private 私有的 只能自己访问,自己的子类不能访问,其他类更不能访问
 1class Father {
 2  public name: string
 3  protected age: number
 4  private money: number
 5
 6  constructor(name: string, age: number, money: number) {
 7    this.name = name
 8    this.age = age
 9    this.money = money
10  }
11  getName(): string {
12    return this.name
13  }
14  setName(name: string): void {
15    this.name = name
16  }
17}
18class child extends Father {
19  constructor(name: string, age: number, money: number) {
20    super(name, age, money)
21  }
22  desc() {
23    console.log(`${this.name}${this.age}${this.money}`)
24    
25  }
26}
27let children = new child('金色小芝麻', 18, 1000)
28console.log(children.name)
29console.log(children.age) 
30console.log(children.money) 
  • 当构造函数修饰为 private 时,该类不允许被继承或者实例化:
 1class Animal {
 2  public name: string;
 3  private constructor(name: string) {
 4    this.name = name;
 5  }
 6}
 7class Cat extends Animal { 
 8  constructor(name: string) {
 9    super(name);
10  }
11}
12
13let a = new Animal('Jack'); 
  • 当构造函数修饰为 protected 时,该类只允许被继承:
 1class Animal {
 2  public name: string;
 3  protected constructor(name: string) {
 4    this.name = name;
 5  }
 6}
 7class Cat extends Animal {
 8  constructor(name: string) {
 9    super(name);
10  }
11}
12
13let a = new Animal('Jack'); 

4、readonly

readonly 修饰的变量只能在属性声明时或 构造函数 中初始化

 1class Animal {
 2  
 3  public readonly name: string
 4  constructor(name: string) {
 5    this.name = name
 6  }
 7  changeName(name: string) {
 8    this.name = name 
 9  }
10}
11let a = new Animal('hello')
12a.name = '111' 
13a.changeName('nihao') 
14console.log(a)

readonly 只是在 编译阶段进行代码检查。运行时依然能打印

5、参数属性

在上面的例子中,都是在类的定义的顶部初始化实例属性,在 constructor 里接收参数然后对实例属性进行赋值,参数属性就是为了简化这一过程的

直接在 constructor 构造函数的参数前面加上修饰符或readonly => 等同于在类中定义该属性同时给该属性赋值,使代码更简洁。

 1class User {
 2  constructor(public name: string) {}
 3}
 4let user = new User('hello')
 5console.log(user.name) 
 6user.name = 'nihao'
 7console.log(user.name) 

6、存取器

  • TypeScript 中,我们可以通过 getter/ setter来改变一个类中属性的读取和赋值行为
 1class Person {
 2  name: string
 3  constructor(name: string) {
 4    this.name = name
 5  }
 6  get getName() { 
 7    return this.name
 8  }
 9  set setName(val: string) { 
10    this.name = val.toUpperCase()
11  }
12}
13let p1 = new Person('nihao')
14console.log(p1.getName)
15p1.setName = 'hello'
16console.log(p1.name)

7、静态属性和静态方法static

使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:

 1class Father {
 2  public name: string
 3  constructor(name: string) {
 4    this.name = name
 5  }
 6  public static className: string = 'Father'
 7  static getClassName(): string {
 8    return Father.className
 9  }
10  
11}
12console.log(Father.className)
13console.log(Father.getClassName())

8、抽象类和抽象方法abstract

使用 abstract 关键字来定义抽象类和在抽象类内部定义抽象方法。

8.1 抽象类

  • 抽象描述一种抽象的概念,做为其它类的基类使用
  • 无法创建抽象类的实例,抽象类只能被继承
 1abstract class Animal {
 2  name!: string
 3  abstract speak(): void
 4}
 5
 6class Cat extends Animal {
 7  speak() {
 8    console.log('喵喵喵')
 9  }
10}
11
12let animal = new Animal(); 
13let cat = new Cat()
14cat.speak() 

8.2 抽象方法

  • 抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且必须实现
  • 抽象方法只能出现在抽象类中
 1abstract class Animal {
 2  name: string
 3  abstract speak(): void = ()=>{} 
 4}
 5class Cat extends Animal {
 6  speak() { 
 7    console.log('喵喵喵')
 8  }
 9}
  • 子类可以对抽象类进行不同的实现
 1abstract class Animal {
 2  abstract speak(): void
 3}
 4class Dog extends Animal {
 5  speak() {
 6    console.log('汪汪汪')
 7  }
 8}
 9
10class Cat extends Animal {
11  speak() {
12    console.log('喵喵喵')
13  }
14}

8.3 抽象类 VS 接口

  • 不同类之间公有的属性或方法,可以抽象成一个接口(interfaces), 而抽象类是供其他类继承的基类
  • 抽象类本质是一个无法被实例化的类,可以包含成员的实现细节,而接口仅能够用于描述,既不能提供方法的实现细节,也不为属性进行初始化
  • 一个类可以继承一个类或抽象类,但可以实现(implements)多个接口
  • 抽象类也可以实现接口
 1abstract class Animal {
 2  name: string;
 3  constructor(name: string) {
 4    this.name = name;
 5  }
 6  abstract speak(): void;
 7}
 8interface Flying {
 9  fly(): void
10}
11interface age {
12  age: number
13}
14class Dog extends Animal implements Flying, age {
15  age: 18
16  speak() {
17    console.log('汪汪汪')
18  }
19  fly() {
20    console.log('我会飞')
21  }
22}

| 访问控制修饰符 | private、protected、public | | 只读属性 | readonly | | 静态属性 | static | | 抽象类、抽象方法 | abstract |

参考文献

[1]. TypeScript中文网

[2]. TypeScript 入门教程

个人笔记记录 2021 ~ 2025