setter 和 getter

有时候我们需要对内部属性做一些保护,不能在类的外部访问,使用private。

但有时候我们希望对内容做一些处理之后再将其暴露出来使用。
我们可以通过 getter/setter来满足。

  1. class Person {
  2. constructor(private name: string) {}
  3. /*
  4. 这里的意思是,我定义了一个getName属性,
  5. 虽然看起来是个方法,但在类的外部以属性的形式调用,返回的是this.name这个私有属性
  6. 这样的做法有什么意义呢?
  7. name 作为私有属性是不想被外部直接调用的,
  8. 我们通过getter这样的写法,可以对数据处理后,再让外界调用,比如:加密
  9. 这样可以确保数据的安全性,很多时候getter的作用在于这里
  10. */
  11. get getName() {
  12. return this.name + 'rose';
  13. }
  14. }
  15. const person = new Person('cos');
  16. // person.name // 这样是会报红的。
  17. console.log(person.getName)

我们一般会在私有属性名称之前,加一个下划线,大部分语言其实都是这么操作的。

  1. class Person {
  2. constructor(private _name: string) {}
  3. /*
  4. 我们一般会在私有属性名称之前,加一个下划线
  5. */
  6. get name() {
  7. return this._name;
  8. }
  9. }
  10. const person = new Person('cos');
  11. console.log(person.name)

因为 _name 是私有属性,所以是不能直接使用 this.name 进行赋值的
我们可以使用setter 来处理这个。

  1. class Person {
  2. constructor(private _name: string) {}
  3. get name() {
  4. return this._name + ' wang';
  5. }
  6. set name(name: string) {
  7. // 这里也可以对_name 做一些处理
  8. const realName = name.split(' ')[0]
  9. this._name = realName;
  10. }
  11. }
  12. const person = new Person('cos');
  13. console.log(person.name) // cos wang
  14. person.name = 'rose wang';
  15. console.log(person.name) // rose wang

单例模式

单例模式:通过单例模式的方法创建的类在当前进程中只有一个实例
那么我们首先就要限制住,不能在外部通过 new Demo()的像是来创建实例

如果我写了 private 那么就会变为私有的 constructor,
外部就不能通过 new 的形式创建 实例。
这样就规避了通过new来创建实例的写法。

那如何去创建唯一的demo实例?

  1. class Demo {
  2. private constructor() {}
  3. // 写public getInstance() 是不能在类上面获取到这个属性的
  4. // 如果想要在类上面去使用一个属性的话,可以使用static
  5. // static 表示把这个方法挂在类上面,而不是类的实例上
  6. static getInstance() {
  7. // 此时我希望通过 Demo.getInstance() 返回一个Demo的实例。可以如下写:
  8. return new Demo()
  9. }
  10. }
  11. const demo1 = Demo.getInstance();
  12. const demo2 = Demo.getInstance();
  13. //但是这样写的时候,每次执行都是new 了一个新的实例,则,demo1 和 demo2指向了不同的实例。

但是这样写的时候,每次执行都是new 了一个新的实例,则,demo1 和 demo2指向了不同的实例。我们改造如下:

  1. class Demo {
  2. // 定义的instance的目的就是为了存储new出来的demo
  3. private static instance: Demo;
  4. private constructor(public name: string) {}
  5. static getInstance() {
  6. if(!this.instance) {
  7. this.instance = new Demo('mock');
  8. }
  9. return this.instance;
  10. // 这样写demo1 和 demo2 是相等的。
  11. }
  12. }
  13. const demo1 = Demo.getInstance();
  14. const demo2 = Demo.getInstance();
  15. console.log(demo1.name)
  16. console.log(demo2.name)

readonly

  1. class Person {
  2. public readonly name: string;
  3. constructor(name: string) {
  4. this.name = name;
  5. }
  6. }
  7. const p1 = new Person('cos');
  8. // p1.name = 'rose'; // name为只读属性的话,这里就不能对其重新赋值了
  9. console.log(p1.name);

抽象类

如果多个类有一些通性,
那么我们就可以定义一些抽象类
注意:抽象类只能被继承,而不能直接被实例化

  1. // 这3个图象的类,都应该有求面积的方法
  2. // 我们可以给每个类定义一个 getArea() 方法,虽然每个类,
  3. // 计算面积的方法是不一样的,但是都有类似的方法。
  4. abstract class Geom {
  5. // 抽象类中也可以定义一些具体的属性或者方法
  6. width: number;
  7. radius: number;
  8. // 如果给类的一个方法加了 abstract 的话,就意味着这个方法的具体实现也是抽象的
  9. // 我们也无法确定具体是怎么实现,所以只能定义一下这个方法而无法具体实现
  10. getType() {
  11. return 'Geom';
  12. }
  13. abstract getArea(): number;
  14. }
  15. // 表示 Circle 是抽象类Geom 的实现类
  16. class Circle extends Geom {
  17. // 直接这么写会报错,
  18. // 子类如果继承了抽象类,抽象类中如果有抽象方法,必须自己去实现这个抽象方法
  19. getArea() {
  20. return 123;
  21. }
  22. }
  23. class Sqare {}
  24. class Triangle {}

抽象类对比接口

抽象类和接口有点类似,
抽象类是把类相关的东西抽象出来
而接口是把对象等通用的东西抽象出来

  1. interface Teacher {
  2. name: string,
  3. teachAge: number
  4. }
  5. interface Student {
  6. name: string,
  7. age: number
  8. }
  9. interface Driver {
  10. name: string,
  11. age: number
  12. }
  13. const teacher = {
  14. name: 'cos',
  15. teachAge: 20
  16. }
  17. const student = {
  18. name: 'rose',
  19. age: 18
  20. }
  21. const driver = {
  22. name: 'jack',
  23. age: 18
  24. }
  25. const getUserInfo = (user: (Teacher | Student)) => {
  26. console.log(user.name);
  27. }
  28. getUserInfo(teacher)
  29. getUserInfo(student)
  30. getUserInfo(driver)

上述的代码中每一项 interface , 都有name属性,所以我们可以继续在做一层抽象,

  1. interface People {
  2. name: string;
  3. }
  4. interface Teacher extends People {
  5. teachAge: number
  6. }
  7. interface Student extends People {
  8. age: number
  9. }
  10. interface Driver extends People {
  11. age: number
  12. }
  13. const teacher = {
  14. name: 'cos',
  15. teachAge: 20
  16. }
  17. const student = {
  18. name: 'rose',
  19. age: 18
  20. }
  21. const driver = {
  22. name: 'jack',
  23. age: 18
  24. }
  25. const getUserInfo = (user: People) => {
  26. console.log(user.name);
  27. }
  28. getUserInfo(teacher)
  29. getUserInfo(student)
  30. getUserInfo(driver)