TS 笔记七 类

一、ES6中的类

参考
js红宝书笔记九 第八章 类与面向对象编程

虽然 ECMAScript 6 类表面上看起来可以支持正式的面向对象编程,但实际上它背后使用的仍然是原型和构造函数的概念。

二、TS类与ES6类的差异

参考
ES6与typescript中的类(class)

1.默认public/privated/protected

私有属性方面ECMAScript目前还没有定案,typescript通过添加private来标记私有属性。

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

// Employee 能够继承 Person
class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }

    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // 错误: 'Person' 的构造函数是被保护的.
2.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 是只读的.
3.getter/setter一致
4.静态属性

ECMAScript目前没有静态属性

在这个例子里,我们使用 static定义 origin,因为它是所有网格都会用到的属性。 每个实例想要访问这个属性的时候,都要在 origin前面加上类名。 如同在实例属性上使用 this.前缀来访问属性一样,这里我们使用 Grid.来访问静态属性。

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

console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));
5.抽象类

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。

ECMAScript目前没有抽象类。

抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 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编程》第五章,使用了type关键字作为类型别名,后续会详解。

type Color = 'Black' | 'White';
type File1 = 'A'|'B'|'C'|'D'|'E'|'F'|'G'|'H';
type Rank = 1|2|3|4|5|6|7|8;

class Position{
    constructor(
        private file:File1,
        private rank:Rank
    ){}

    distanceFrom(position:Position){
        return{
            rank:Math.abs(position.rank - this.rank),
            file:Math.abs(position.file.charCodeAt(0)-this.file.charCodeAt(0))
        };
    }

    test(){
        let v = this.distanceFrom(new Position('A',2));
        console.log(v.file,typeof v);
    }
}

abstract class Piece{
    protected position:Position;

    constructor(
        //初始赋值后,color只能读取
        private readonly color:Color,
        file:File1,
        rank:Rank
    ){
        this.position = new Position(file,rank);
    }

    //默认实现,子类可以覆盖
    moveTo(position:Position){
        this.position = position;
    }

    //子类必须实现,实现抽象类时也要实现抽象方法
    abstract canMoveTo(position:Position):boolean;
}

class King extends Piece{
    //这个必须实现,否则报错
    canMoveTo(position:Position){
        let distance = this.position.distanceFrom(position);
        return distance.rank < 2 && distance.file < 2;
    }
}

class Game{
    private pieces = Game.makePieces();

    private static makePieces(){
        return [
            new King('White','E',1),
            new King('Black','E',8),
            //...
        ];
    }
}

let t = new Position('C',2);
t.test();

四、super关键字

与JS一样,TS也支持super调用。如果子类覆盖父类中定义的方法,比如Queen和Piece都实现了take方法,在子类中可以使用super调用父类中的同名方法(例如super.take)。

另一种是super(),必须在构造方法中调用,把父子关系连接起来。

注意,super只能访问父类的方法,不能访问父类的属性。

你可能感兴趣的:(TS 笔记七 类)