TypeScript中的类修饰符和抽象类

8/22/2021 Typescript

在 TypeScript 中,类的属性和方法可以使用不同的修饰符来限制它们的可见性和行为。本文将介绍 TypeScript 中常用的类修饰符和抽象类的概念以及它们的用法。

# 类的修饰符

在 TypeScript 中,类的属性和方法可以使用以下修饰符进行修饰:

# public

public 是默认的修饰符,表示属性和方法可以在类的内部、继承类和类的实例中自由访问。这是最宽松的修饰符。

class Animal {
    public name: string;
    constructor(theName: string) {
        this.name = theName;
    }
    public move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

// 等价于
class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

# protected

protected 修饰符稍微严格一些,只有类的内部和继承类中可以访问,类的实例不能访问。

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

class Employee extends Person {
    constructor(name: string) {
        super(name);
    }
    public getElevatorPitch() {
        return `Hello, my name is ${this.name}.}`;
    }
}

let howard = new Employee("Howard");
console.log(howard.getElevatorPitch());
console.log(howard.name); // 错误

# private

private 是最严格的修饰符,只有类的内部可以访问,继承类和类的实例都不能访问。

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

class Employee extends Person {
    constructor(name: string) {
        super(name);
    }
    public getElevatorPitch() {
        return `Hello, my name is ${this.name}.}`; // 错误
    }
}

let howard = new Person("Howard");
console.log(howard.name); // 错误

# readonly

readonly 修饰符表示属性是只读的,必须在声明时或构造函数中初始化。它可以修饰普通属性,也可以修饰构造函数的参数,称为参数属性。

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor(theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误,name 是只读的。

class Octopus {
    readonly numberOfLegs: number = 8;
    constructor(readonly name: string) {
    }
}

# static

static 修饰符表示属性和方法属于类本身,而不是类的实例。它可以通过类名来访问,而不需要创建类的实例。

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);
    }
    constructor (public scale: number) { }
}

let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale

console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(Grid.origin); // 可以直接访问静态属性

# 抽象类(abstract)

抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类可以包含抽象方法,这些方法必须在派生类中被实现。抽象方法的定义使用 abstract 修饰符。

abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
        console.log('Department name: ' + this.name);
    }

    abstract printMeeting(): void; // 必须在派生类中实现
}

class AccountingDepartment extends Department {

    constructor() {
        super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
    }

    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }

    generateReports(): void {
        console.log('Generating accounting reports...');
    }
}

let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误: 方法在声明的抽象类中不存在

抽象类在设计模式中常用于定义接口和基类,它提供了一种定义标准和约束子类的方式。

通过类的修饰符和抽象类的概念,TypeScript 提供了更加丰富的面向对象编程工具,可以帮助您更好地组织和管理代码。