Class(类)分享 第四节

一、基础

// es6 普通的一个类
// 构造函数为实例添加成员,类的所有方法都定义在类的prototype属性,即原型上面。
class Animal {
  name
  constructor(name, age){
    this.name = name
  }
	move(distance){
  	console.log(`The speed of ${this.name} is ${distance}m/s`)
  }
}
let a = new Animal("Tom")
console.log(a.move(5))

//ts, 成员,参数,函数返回值加上类型检查,实例加上类类型
class Animal { // 声明了类的实例的类型
  name: string
  constructor(name: string){
    this.name = name
  }
  move(distance: number): void{
  	console.log(`The speed of ${this.name} is ${distance}m/s`)
  }
}
let a: Animal = new Animal("Tom")
console.log(a.move(5))

二、继承

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

class Animal {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s`)
  }
}
​
class Cat extends Animal {
  catkind
  // 子类有构造函数,必须使用super调用父类构造方法
  constructor(name: string, age: number, catkind: string) {
    super(name, age)
    this.catkind = catkind
  }
  // 重写move
  move(distance: number): void {
    console.log("cat walking...");
    super.move(distance)
  }
}
​
class Dog extends Animal {
  dogkind
  constructor(name: string, age: number, dogkind: string) {
    super(name, age)
    this.dogkind = dogkind
  }
  move(distance: number): void {
    console.log("dog walking...");
    super.move(distance)
  }
}
​
let cat1: Cat = new Cat("Tom", 5, "persian")
console.log(`${cat1.name} is ${cat1.age} years old,its kind is ${cat1.catkind} cat`)
console.log(cat1.move(5))
​
let dog1: Dog = new Dog("jack", 3, "Husky")
console.log(`${dog1.name} is ${dog1.age} years old,its kind is ${dog1.dogkind} dog`)
console.log(dog1.move(10))

三、public private 和 protected

  • public:默认所有的成员和方法都是public。修饰的成员和方法是公开的,可以在任何地方被访问到
  • private: 修饰的成员和方法是私有的的,只能在声明它的类的内部被访问, 不允许被实例和子类访问
  • protected:修饰的成员和方法是受保护的,只能在声明它的类和子类的内部被访问, 不允许被实例访问
// 1. public
class Animal {
  public name: string;
  public constructor(name: string) {
    this.name = name;
  }
  public move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s。`)
  }
}
​
let cat1 = new Animal("Tom")
console.log(cat1.name)
console.log(cat1.move(5))
​
// 2.1 private-成员
class Animal {
  private name: string;
  public constructor(name: string) {
    this.name = name;
  }
  public move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s。`)
  }
}
​
let cat1 = new Animal('Tom');
console.log(cat1);
console.log(cat1.name); // error 实例不能访问
console.log(cat1.move(85)); // 类内部可以访问
​
​
class Cat extends Animal{
  public constructor(name: string){
    super(name);
  }
  public say() {
    console.log(`${this.name} say miao~miao~`);
  }
} 
​
let cat2 = new Cat('haha');
console.log(cat2.name) // error 在子类的实例中也不能被访问
​
// 2.2 private-构造函数
// 构造函数修饰为 private 时,该类不允许被继承或者实例化
class Animal {
  public name;
  private constructor(name) {
    this.name = name;
  }
}
class Cat extends Animal { // error a. 不能被继承
  constructor(name) {
    super(name);
  }
}
let cat1 = new Animal('Jack'); // error b. 不能被实例化
​
// 3.1 protected-成员
class Animal {
  protected name: string;
  public constructor(name: string) {
    this.name = name;
  }
  public move(distance: number): void {
    console.log(`The speed of ${this.name} is ${distance}m/s。`)
  }
}
​
let cat1 = new Animal('Tom');
console.log(cat1.move(85)); // 类内部可以访问
console.log(cat1.name); // error  实例不能访问
​
class Cat extends Animal{
  public constructor(name: string){
    super(name);
  }
  public say() {
      console.log(`${this.name} say miao~miao~`); // 在子类中可以访问
  }
} 
let cat2 = new Cat('haha');
console.log(cat2.say())
console.log(cat2.name) // error 在子类的实例中也不能被访问
​
// 3.2 protected-构造函数
// 构造函数修饰为 protected 时,该类只允许被继承
class Animal {
  public name;
  protected constructor(name) {
    this.name = name;
  }
}
class Cat extends Animal {
  constructor(name) {
    super(name);
  }
}
​
let a = new Animal('Jack'); // error 不能被实例化

四、readonly

使用readonly关键字将成员设置为只读的。 只读成员必须在声明时或构造函数里被初始化。

class Animal {
  readonly name: string;
  readonly age: number = 18; // 声明时初始化
  public constructor(name: string) {
    this.name = name;  // 构造函数里初始化
  }
}
​
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom'; // error 只读

注意如果readonly和其他访问修饰符同时存在的话,需要写在其后面。

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

五、参数属性

一般,我们先声明类的成员和构造函数内赋值。通过参数属性,我们将声明和赋值合并起来。

// 一般
class Animal {
  public name: string;
  public constructor(name: string) {
    this.name = name;
  }
}
let a = new Animal('Jack');
console.log(a.name); // Jack
​
// 参数属性
class Animal {
  // public name: string; // 省略
  public constructor(public name: string) {
    // 参数属性,必须有修饰符  public,protected,private或readonly
    // this.name = name;  // 可省略
  }
}
let a = new Animal('Jack');
console.log(a.name); // Jack

六、存取器

使用 getter 和 setter 可以改变属性的赋值和读取行为。当类成员上定义存取器时,就不能使用正常成员声明

class Animal {
  // name: string   成员声明
  constructor(name: string) {
    this.name = name;
  }
  get name() {  // 存取器
    return 'Jack';
  }
  set name(value) {
    console.log('setter: ' + value);
  }
}
​
let a = new Animal('Kitty');
a.name = 'Tom';
console.log(a.name);

七、静态属性

可以通过static定义创建类的静态成员和方法,这些成员和方法存在于类的本身而不是类的实例上。只能通过类名访问,不能被构造函数实例化

class Animal {
  static firstWord = "hello";
  constructor(public name: string){}
  sayHi(){
    console.log(Animal.firstWord)
  }
  static isAnimal(animal: Animal): void {
    console.log(animal instanceof Animal);
  }
}
let a = new Animal("Tom")
​
console.log(Animal.firstWord)
Animal.isAnimal(a)
​
console.log(a.firstWord) // error, 实例不能访问
a.isAnimal(a) // error
a.sayHi()

八、抽象类

abstract用于定义抽象类和其中的抽象方法。顾名思义,抽象类和抽象方法是对对一些对象的属性和行为进行高度抽象,一般不包含具体实现细节,所以基类使用。所以,抽象类是不允许被实例化的。其次,抽象类中的抽象方法必须被子类实现,因为一般不包含实现细节。

abstract class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  } 
  abstract move(distance: number): void;
}
​
class Cat extends Animal {
  constructor(name: string) {
    super(name)
  }
  move(distance: number): void { // 必须实现基类的抽象方法
    console.log(`The speed of ${this.name} is ${distance}m/s`)
  }
}
​
let a = new Animal('Jack'); // error,不允许实例化
let cat = new Cat('Tom');
cat.move(5)

九、类和接口

一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的属性和行为,这时候就可以把这些通用属性和方法提取成接口(interfaces),用implements关键字来实现。

举例,门是一个类,防盗门是它的子类。车也是一个类,车和防盗门都有报警功能,将其提取成一个报警方法。作为一个接口,防盗门和车等都可以实现它。

interface Alarm {
    alert(): void;
}
​
class Door {
}
​
class SecurityDoor extends Door implements Alarm {
    alert() {
        console.log('SecurityDoor alert');
    }
}
​
class Car implements Alarm {
    alert() {
        console.log('Car alert');
    }
}

一个类只能继承自一个类,但也可以实现多个接口

interface Alarm { // 报警
alert(): void;
}
​
interface controlDoor {  // 开关门
openDoor(): void;
closeDoor(): void;
}
​
class Car implements Alarm, controlDoor {
alert() {
console.log('Car alert');
}
openDoor() {
console.log('Car door open');
}
closeDoor() {
console.log('Car door close');
}
}

类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。

class Point {
    x: number;
    y: number;
}
interface Point3d extends Point { // 类可以被当作接口使用
    z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
posted @ 2020-11-26 15:28  yxl87  阅读(93)  评论(0编辑  收藏  举报