类相关概念

  • 类(Class):定义了一件事物的抽象特点,包含它的属性和方法
  • 对象(Object):类的实例,通过 new 生成
  • 面向对象(OOP)的三大特性:封装、继承、多态
  • 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
  • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
  • 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat
  • 存取器(getter & setter):用以改变属性的读取和赋值行为
  • 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法
  • 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
  • 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口
  • 类直接作为类型实际上就是实例的类型,而typeof class则是完整的类的类型(包括prototype等)

    TS中使用类

    1. 三种访问修饰符

  • public 默认的都是public,可以在类的**外部****内部**使用

  • private 只能在类的**内部**使用,**外部****继承**中都不可以使用
  • protected 除了在**外部**不可使用 ```javascript class Animal { private name; public constructor(name) { this.name = name; } } // private修饰的不允许被访问 let a = new Animal(“Jack”); console.log(a.name); a.name = “Tom”; // private修饰的在子类中也不允许被访问 class Cat extends Animal { constructor(name) { super(name); console.log(this.name); // // 报错:属性“name”为私有属性,只能在类“Animal”中访问。 } }

// 当构造函数修饰为 private 时,该类不允许被继承或者实例化: class Animal { public name; private constructor(name) { this.name = name; } } class Cat extends Animal { // 报错:无法扩展类“Animal”。类构造函数标记为私有。 constructor(name) { super(name); } } let a = new Animal(‘Jack’); // 报错:类“Animal”的构造函数是私有的,仅可在类声明中访问。

  1. ```javascript
  2. // 用 protected 修饰,则允许在子类中访问:
  3. class Animal {
  4. protected name;
  5. public constructor(name) {
  6. this.name = name;
  7. }
  8. }
  9. class Cat extends Animal {
  10. constructor(name) {
  11. super(name);
  12. console.log(this.name);
  13. }
  14. }
  15. // 当构造函数修饰为 protected 时,该类只允许被继承:
  16. class Animal {
  17. public name;
  18. protected constructor(name) {
  19. this.name = name;
  20. }
  21. }
  22. class Cat extends Animal {
  23. constructor(name) {
  24. super(name);
  25. }
  26. }
  27. let a = new Animal('Jack'); // 报错:类“Animal”的构造函数是受保护的,仅可在类声明中访问。

2. readonly

readonly指定属性为只读,初始化后就不能再修改(const),可以在声明时的时候就初始化它们:

  1. function foo(config: { readonly bar: number, readonly bas: number }) {
  2. // ..
  3. }
  4. const config = { bar: 123, bas: 123 }; // 初始化后,后面不能再改变
  5. foo(config);
  6. class Foo {
  7. readonly bar = 1; // 也可以在声明的时候初始化 OK
  8. readonly baz: string = 'world';
  9. constructor() { // ⭐constuctor中的操作都是初始化
  10. this.baz = 'hello'; // OK
  11. }
  12. // 只含有 getter 但是没有 setter 的属性,自动被推断为只读:
  13. class Person {
  14. get fullName() {
  15. return this.firstName + this.lastName;
  16. }
  17. }

可以搞一个Readonly 的映射类型,接收一个泛型 T,用来把它的所有属性标记为只读类型:

  1. type Foo = {
  2. bar: number;
  3. bas: number;
  4. };
  5. const foo: Foo = { bar: 123, bas: 456 };
  6. foo.bar = 456; // ok
  7. type FooReadonly = Readonly<Foo>;
  8. const fooReadonly: FooReadonly = { bar: 123, bas: 456 };
  9. fooReadonly.bar = 456; // Error: bar 属性只读

TypeScript 提供ReadonlyArray<T>接口,相当于readonly <T>[],不允许操作数组的索引,但是可以给数组重新赋值:

  1. let foo: ReadonlyArray<number> = [1, 2, 3];
  2. console.log(foo[0]); // ok
  3. foo.push(4); // Error: 类型“readonly number[]”上不存在属性“push”。
  4. foo = [1, 2]; // ok, 重新赋值不受影响
  5. foo[0] = 4 // Error:类型“readonly number[]”中的索引签名仅允许读取。

3. 参数修饰符

修饰符和readonly还可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值,使代码更简洁:

  1. class Animal {
  2. // public name: string;
  3. public constructor(public name) {
  4. // this.name = name;
  5. }
  6. }
  7. // 注意如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面。
  8. class Animal {
  9. // public readonly name;
  10. public constructor(public readonly name) {
  11. // this.name = name;
  12. }
  13. }

3. 抽象类

abstract 用于定义抽象类和其中的抽象方法。

  • 抽象类是不允许被实例化的: ```javascript abstract class Animal { public name; public constructor(name) { this.name = name; } public abstract sayHi(); }

let a = new Animal(‘Jack’); // 报错:无法创建抽象类的实例。

  1. - 抽象类中的抽象方法必须被子类实现:
  2. ```javascript
  3. abstract class Animal {
  4. public name;
  5. public constructor(name) {
  6. this.name = name;
  7. }
  8. public abstract sayHi();
  9. }
  10. class Cat extends Animal {// 报错:非抽象类“Cat”不会实现继承自“Animal”类的抽象成员“sayHi”。
  11. public eat() {
  12. console.log(`${this.name} is eating.`);
  13. }
  14. }