一、介绍

TypeScript 的 class 和 ES2015 的 class 并不是完全一样的概念,ES6 的 class 仅仅是一种语法糖,但是这种语法糖已经成为标准,并且(新)浏览器内核基本支持,而平时使用的时候,基本都是通过 webpack 或者 gulp 这种进行兼容或者打包。

而 TypeScript 的 class 可以使得开发者在不依赖 ES5 的环境下直接使用,不需要等到下个 JS 版本。

二、类的声明

class 的声明语法类似 C# 或者 Java:

class Person {
    name: String;
    constructor(name: String) {
        this.name = name;
    }
    talk(message: String) {
        return 'Hello: ' + message
    }
}

let Tom = new Person('tom');

上面代码编译后的结果如下,可以发现,TypeScript 直接编译成 ES5 的语法,并没有继续编译成 ES6 的语法

1.jpg

三、继承 extends

比如上面的类 Person,现在需要男人和女人两个类(有些时候并不是直接加个成员属性这么简单,可能有很多不同的地方):

class Men extends Person {
    sex: 'male';
    showSex() {
        console.log('Hi, I am ' + this.sex);
    }
}

const Tom = new Men('tom');
Tom.talk();
Tom.showSex();

编译结果:

2.jpg

如果子类构造参数中需要更多参数,而不仅仅是从基类继承下来的参数,则需要通过 super() 来调用父组件的构造参数:

class Men extends Person {
    sex: String;
    favorite: String
    constructor(name: String, favorite: String) {
        super(name); // 调用基类构造方法
        this.favorite = favorite;
    }
    showSex() {
        console.log('Hi, I am ' + this.sex);
    }
}
const Tom = new Men('tom', 'football');
Tom.talk('i am tom');
Tom.showSex();

四、属性修饰符

1、public 默认

一些语言的默认属性修饰符是 protected,而 TypeScript 中成员属性默认都是 public,除了默认之外,也可以强制手动指定。

public 声明的成员属性或者方法类的实例可以访问。

class Person {
    public name: String;
    constructor(name: String) {
        this.name = name;
    }
    public talk(message: String) :void {
        console.log(message);
    }
}

2、private

私有属性是不允许类的实例访问的。

class Person {
    private name: String;
    constructor(name: String) {
        this.name = name;
    }
    public getName() {
        return this.name;    
    }
}
const Tom = new Person('tom');
Tom.name;
Tom.getName();

3.jpg

private 在子类中,也是无法访问的:

class Person {
    private name: String;
    constructor(name: String) {
        this.name = name;
    }
    public getName() {
        return this.name;    
    }
}

class Male extends Person { 
    constructor(name: String) {
        super(name);
    }
    getName() { 
        return this.name;
    }
}

4、.jpg

3、protected

protected 声明的成员在派生类中仍然可以访问,上面的代码将 private 改成 protected 声明则不会报错:

class Person {
    protected name: String;
    constructor(name: String) {
        this.name = name;
    }
    public getName() {
        return this.name;    
    }
}

class Male extends Person { 
    constructor(name: String) {
        super(name);
    }
    getName() { 
        return this.name;
    }
}

protected 声明的成员也是无法通过实例访问的:

5.jpg

构造函数如果使用 protected 声明,说明这个类不能被实例化,只能被继承

4、readonly 修饰符

readonly 修饰符用于将属性设置为只读,如果要设置值,则只能在声明或者是在构造函数中初始化内容:

class Person {
    readonly  name: String;
    constructor(name: String) {
        this.name = name;
    }
    public getName() {
        return this.name;    
    }
}

5、参数属性

参数属性是比较特别的东西,可以让我们将属性的赋值自动和属性关联在一起,而不需要在构造方法中去手动赋值:

class Person {
    readonly  age: Number = 18;
    constructor(readonly name: String) {}
    public getName() {
        return this.name;    
    }
}

上面代码中,在构造方法内部不需要手动进行 this.name = name 的操作,通过 readonly name:String 直接将参数 name 与 this.name 关联。

五、存取器

TypeScript 支持通过 getters/setters 来截取对对象成员的访问。

存取器在 Java 里面用的特别多,Java 的存取器样板代码也非常多,存取器一般对于 私有属性特别有用,而一般的属性都建议设置成私有属性,因为属性是不能随便更改的。

class Person {
    private _name: String;
    constructor(name: String) {
        this._name = name;
    }
    get name(): String {
        return name;
    }
    set name(newName: String) {
        this._name = newName.trim();
    }
}

需要注意的是,set 方法不能有返回值,哪怕是 void

上面代码编译后,会发现,实际上 set 和 get 属性,是通过 Object.defineProperty 方式声明的

6.jpg

六、静态属性

静态属性不允许继承并且不允许类的实例访问,只能通过类本身访问静态属性。

class Person {
    static newName: String = 'name';
    constructor() { }
}

const Tom = new Person();
Person.newName;
Tom.newName;

7.jpg

七、抽象类

抽象类作为其他子类的基类,一般不进行直接实例化,和接口不同的是,抽象类可以去实现成员属性或者是方法,然后子类再去覆写成员属性或者方法。

abstract class Person {
    abstract talk(): void;
    walk(): void {
        console.log('...')
    }
}

和其他高级语言的面向对象抽象类一样,如果一个方法被定义为 abtract,则这个方法可以不在基类中实现,但是它的子类必须去实现这个方法。

abstract class Person {
    abstract talk(): void;
    walk(): void {
        console.log('...')
    }
}

class Male extends Person{ 

}

8.jpg