TypeScript | 关于class的那些事

666 阅读3分钟

「这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

TypeScript已经很盛行了,成为前端必备的基础语言技能,这里我们整理下class的那些基础知识点。

1. 类的基本实现

  1. 类成员的属性都是实例属性,而不是原型属性;
  2. 类成员方法都是原型方法。
class Dog{
  constructor(name:string){
        this.name = name;
    }
    name:string //成员属性添加类型注解
  run(){}  //挂载到Dog.prototype上
}

 2. 类的继承

类的继承一定要存在super,它代表父类的实例。

class Husky extends Dog{
    constructor(name:string,color:string){
       // 强制规定
       super(name)
       this.color = this.color;
    }
    color:string
}

 3. 类的成员修饰符

  1. 构造器被private修饰,则类不能被实例化和被继承
  2. public公有,对所有可见
  3. private私有,类本身可访问,实例或子类都不能访问
  4. protected保护成员,类和子类可访问,不能被实例访问
  5. static静态成员,只能被类名来调用,可以被子类继承
class Dog1{
    //类不能被实例化、也不能被继承
    private constructor(public color:string){//color变成实例属性

    }
    //public:公有,默认,对所有可见
    public name:string
    //private:私有,类本身访问,不能被类的实例/子类访问
    private pri(){}
    //protected:受保护成员,只能在类和子类访问,不能被实例访问
    protected pro(){}
    //只读属性,不可被更改,要赋初始值
    readonly legs:number = 4
    //静态成员:只能通过类名来调用,不能通过实例调用,可以被子类继承
    static food:string = 'bones'
}

4. this的用法

this指向当前class

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

// 返回this,实现了方法链式调用
new WorkFlow().step1().step2();

//继承的时候this表现出多态,可能是父类或者子类
class MyFlow extends WorkFlow{
  next(){
      return this; //返回子类类型
  }
}
// 子类-->父类
new MyFlow().next().step1().next().step2();

5. 存储器

TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

let passcode = "secret passcode";

class Employee {
    private _fullName: string;

    get fullName(): string {
        return this._fullName;
    }

    set fullName(newName: string) {  
        // 当密码不对,则无法修改
        if (passcode && passcode == "secret passcode") {
            this._fullName = newName;
        }
        else {
            console.log("Error: Unauthorized update of employee!");
        }
    }
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
    alert(employee.fullName);
}
6. 静态属性

到目前为止,我们只讨论了类的实例成员,那些仅当类被实例化的时候才会被初始化的属性。 我们也可以创建类的静态成员,这些属性存在于类本身上面而不是类的实例上。

class Grid {
    static origin = {x: 0, y: 0};
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor (public scale: number) { }
}

let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale
7. 抽象类
  1. 抽象类做为其它派生类的基类使用,可以包含成员的实现细节。 
  2. abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。
  3. 能被继承,不能被实例;
  4. 抽离出事务的共性,有利于代码的复用和扩展;
  5. 抽象类可以实现多态:父类中定义抽象方法,在多个子类中对这个方法有不同实现, 程序运行时候根据不同对象执行不同操作,实现了运行时的绑定;
  6. 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 
  7. 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。
  8. 抽象方法必须包含 abstract关键字并且可以包含访问修饰符。
abstract class Animal {
    constructor() {
    }
    eat(){}
    //抽象方法:不指定具体的实现,明确知道子类有具体的实现
    abstract sleep():void
}
//new Animal() 报错:不能被实例

class Cat extends Animal {
    constructor(name:string) {
        super()
        this.name=name
    }
    name:string
    run(){}
    sleep(){
        console.log('cat is sleep')
    }
}

class Pig extends Animal{
    constructor() {
        super();
    }
    sleep(){console.log('pig is sleep')}
}

//多态
let animals:Animal[] = [new Cat('1'),new Pig()];
animals.forEach(i=>{
    i.sleep();
})

总结

至此便完成了TypeScript的学习。