阅读 385

构建 Typescript 知识体系(三)-TS class 浅析

这是我参与更文挑战的第九天,活动详情查看:更文挑战

无论 ES 还是 TS 中, 类成员都是实例属性,类成员方法都是实例方法

一. TS 中 class 的特点

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  name: string;

  run() {}
}
复制代码
console.log(Dog.prototype);
// {run: ƒ, constructor: ƒ}

/*
打印出类的原型,
结果是不包含类的成员的, 只有  run(), constructor()
*/
复制代码

1.1 成员属性只在实例上, 而不在原型上

let dog = new Dog("大黄");
console.log(dog);
// Dog {name: "大黄"}

/*
可以看出name属性只在实例上, 而不在原型上
*/
复制代码

2.1 实例的属性必须具有初始值,或者在构造函数中被初始化

class Dog1 {
  constructor(name: string) {
    // this.name = name;
  }
  // 错误提示: 属性“name”没有初始化表达式,且未在构造函数中明确赋值。ts(2564)
  name: string;

  run() {}
}
复制代码

解决

class Dog1 {
  constructor(name: string) {
    // this.name = name;
  }
  name: string = "dog";

  run() {}
}

// 或者
class Dog2 {
  constructor(name: string) {
    this.name = name;
  }
  name: string;

  run() {}
}
复制代码

二. 类的继承

class Cat0 extends Dog {
  //错误提示: 派生类的构造函数必须包含 "super" 调用。ts(2377)
  constructor() {}
}
复制代码

解决 super 代表父类的实例

class Cat extends Dog {
  constructor(name: string, color: string) {
    super(name);
    this.color = color;
  }
  color: string;
}
复制代码

三. 类的成员修饰符

1. 共有成员-public

类的所有属性默认都是 public,当然也可以直接申明出来

class Dog1 {
  constructor(name: string) {
    // this.name = name;
  }
  public name: string = "dog";

  run() {}
}
复制代码

2. 私有成员-private

私有成员只能被类本身调用,而不能被类的实例调用,有不能被子类调用

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  public name: string;

  run() {}

  private walk() {}
}

let dog = new Dog("大黄");

// 错误提示:  属性“walk”为私有属性,只能在类“Dog”中访问。ts(2341)
dog.walk();

class Cat extends Dog {
  constructor(name: string, color: string) {
    super(name);
    this.color = color;
    // 错误提示:  属性“walk”为私有属性,只能在类“Dog”中访问。ts(2341)
    this.walk = () => {};
  }
  color: string;
}
复制代码

可以给构造函数添加私有成员属性,表示该类既不能被实例化,也不能被继承

class Dog {
  private constructor(name: string) {
    this.name = name;
  }
  public name: string;

  run() {}

  private walk() {}
}
// 错误提示:  类“Dog”的构造函数是私有的,仅可在类声明中访问。ts(2673)
let dog = new Dog("大黄");

// 错误提示:  无法扩展类“Dog”。类构造函数标记为私有。ts(2675)
class Cat extends Dog {
  constructor(name: string, color: string) {
    super(name);
    this.color = color;
  }
  color: string;
}
复制代码

3. 受保护成员-protect

受保护成员只能在类及其子类中访问, 而不能再类的实例中访问

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  public name: string;

  protected shout() {}
}

let dog = new Dog("大黄");
// 错误提示: 属性“shout”受保护,只能在类“Dog”及其子类中访问。ts(2445)
dog.shout();

class Cat extends Dog {
  constructor(name: string, color: string) {
    super(name);
    this.color = color;
    // 可以正常访问和执行
    this.shout();
  }
  color: string;
}
复制代码

可以给构造函数添加受保护成员属性,表示该类不能被实例化,只能被继承,相当于申明一个基类

4. 只读属性

只读属性表示不能被更改,并且一定要被初始化

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  public name: string;

  readonly foots: number = 4;
}
复制代码

5. 静态成员-static

类的静态成员只能通过类名来调用,二不能通过子类调用

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  public name: string;

  static food = "bones";
}

let dog = new Dog("大黄");
// bones
console.log(Dog.food);
// 错误提示: 属性 "food" 不是类型为 "Dog" 的静态成员ts(2576)
console.log(dog.food);
复制代码

类的静态成员也可以被继承

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  public name: string;

  static food = "bones";
}

class Cat extends Dog {
  constructor(name: string, color: string) {
    super(name);
    this.color = color;
  }
  color: string;
}

// bones
console.log("Cat.food :", Cat.food);
复制代码

ES 中并没有抽象类的概念,TS 对此进行了扩展

抽象类

抽象类: 只能被继承,不能被实例化的类

abstract class Animal {
  constructor() {}
}
// 无法创建抽象类的实例。ts(2511)
let animal = new Animal();
复制代码

可以在抽象类中定义一个具体的方法并有相关实现 这样子类就可以直接使用,而不用重复实现---实现了方法的复用

abstract class Animal {
  constructor() {}
  eat() {
    console.log("eat");
  }
}

class Pig extends Animal {
  constructor(name: string) {
    super();
    this.name = name;
  }
  public name: string;

  static food = "bones";
}

let pig = new Pig("佩奇");

pig.eat();
复制代码

多态

可以在抽象类中定义一个方法但不具体实现,形成一个抽象方法 **抽象方法的好处是可以在子类中有多种方式实现, **

abstract class Animal {
  constructor() {}

  abstract sleep(): void;
}

class Pig extends Animal {
  constructor(name: string) {
    super();
    this.name = name;
  }
  public name: string;

  sleep() {
    console.log("站着睡");
  }
}

let pig = new Pig("佩奇");

pig.sleep();

class Cat extends Animal {
  sleep() {
    console.log("趴着睡");
  }
}
let cat = new Cat();
cat.sleep();
复制代码

特殊的 TS 类型: this 类型

类的成员方法可以直接返回一个 this, 这样就可以很方便的实现链式调用

class WorkFlow {
  step1() {
    return this;
  }
  step2() {
    return this;
  }
}

let workFlow = new WorkFlow();

workFlow.step1().step2();
复制代码

在继承的时候,this 也可以表现出多态(this 既可以是父类型,也可以是子类型)

class WorkFlow {
  step1() {
    return this;
  }
  step2() {
    return this;
  }
}

let workFlow = new WorkFlow();

workFlow.step1().step2();

class MyFlow extends WorkFlow {
  next() {
    return this;
  }
}

let myflow = new MyFlow();

// myflow.next():  MyFlow {}
console.log("myflow.next(): ", myflow.next());

// myflow.next().step1():  MyFlow {}
console.log("myflow.next().step1(): ", myflow.next().step1().next().step2());
复制代码
文章分类
前端
文章标签