typescript 類

日期: 2019 年 9 月2 日

類的例子

/**
* @description 類
* @class Greeter
*/
class Greeter{
    greeting: string;
    constructor(message: string){
        this.greeting = message;
    }
    greet(){
        return "Hello, " + this.greeting;
    }
}
let greeter = new Greeter("world");
console.log(greeter.greet());

繼承

基于類的程序設(shè)計中一種最基本的模式是允許使用繼承來擴展現(xiàn)有的類


/**
* @description 類的繼承
* @class Animal
*/
class Animal{
    move(distance: number= 0): void{
        console.log(`Animal moved ${ distance } meters.`)
    }
}
class Dog extends Animal{
    bark(){
        console.log("Woof,wang wang...");
    }
}
let dog = new Dog();
    dog.bark();
    dog.move();
    dog.move(10);

這個例子展示了最基本的繼承:類從基類中繼承了屬性和方法。 這里, Dog是一個 派生類,它派生自 Animal 基類,通過 extends關(guān)鍵字。 派生類通常被稱作 子類,基類通常被稱作 超類


一個更加復(fù)雜的類繼承的例子:


/**
* @description 復(fù)雜的類繼承的例子
* @class Animals
*/
class Animals{
    name: string;
    constructor(myName: string){
        this.name = myName;
    }
    move(distance: number= 22){
        console.log(`${this.name} moved ${ distance } meters.`);
    }
}

class Horse extends Animals{
    constructor(name: string){
        super(name);
    }
    move(distance: number= 233){
        console.log('Horse, horse..');
        super.move(distance);
    }
}

class Cat extends Animals{
    constructor(name: string){
        super(name);
    }
    move(distance: number= 23){
        console.log("喵喵喵...");
        super.move(distance);
    }
}

let horse = new Horse("black Horse");
    horse.move();
    horse.move(222);
let cat = new Cat("little cat");
    cat.move();
    cat.move(123);

這個例子演示了如何在子類里可以重寫父類的方法

公有、私有與受保護的修飾符

默認為 public

在TypeScript里,成員都默認為 public。你也可以明確的將一個成員標(biāo)記成 public


/**
* @description typescript 中,成員默認都是 public
* @class Haha
*/
class Haha{
public name: string;
public constructor(theName: string){
this.name = theName;
}
public greet(){
console.log(`Hello, ${ this.name }`);
}
}
let haha = new Haha("Lee");
console.log(haha.name);

私有 private

當(dāng)成員被標(biāo)記成 private時,它就不能在聲明它的類的外部訪問


/**
* @description 當(dāng)成員被標(biāo)記成 private 時,就不能在聲明它的類外訪問它
* @class Hahah
*/
class Hahah{
    private name: string;
    constructor(theName: string){
        this.name = theName;
    }
    printName(){
        console.log(this.name);
    }
}
class Hah extends Hahah{
    constructor(name: string){
        super(name);
    }
    // sayHello(){   // error
    // console.log(`Hello, ${ this.name }`)
    // }
}
let ha = new Hahah('hello');
    ha.printName();
    // ha.name;  // error

TypeScript使用的是結(jié)構(gòu)性類型系統(tǒng)。 當(dāng)我們比較兩種不同的類型時,并不在乎它們從何處而來,如果所有成員的類型都是兼容的,我們就認為它們的類型是兼容的,當(dāng)我們比較帶有 private或 protected成員的類型的時候,情況就不同了。 如果其中一個類型里包含一個 private成員,那么只有當(dāng)另外一個類型中也存在這樣一個 private成員, 并且它們都是來自同一處聲明時,我們才認為這兩個類型是兼容的。 對于 protected成員也使用這個規(guī)則。


/**
* @description 如果其中一個類型里包含一個 private成員,
* 那么只有當(dāng)另外一個類型中也存在這樣一個 private成員,
* 并且它們都是來自同一處聲明時,我們才認為這兩個類型是兼容的
* @class Fruit
*/
class Fruit{
    private name: string;
    constructor(theName: string){
        this.name = theName;
    }
}

class Apple extends Fruit{
    constructor(){
        super("apple");
    }
}

class Employe{
    private name: string;
    constructor(theName: string){
        this.name = theName;
    }
}
let fruit = new Fruit("pine-apple");
let apple = new Apple();
let employe = new Employe("Tom");
    fruit = apple;
    // fruit = employe; // error
    
protected

protected修飾符與 private修飾符的行為很相似,但有一點不同, protected成員在派生類中仍然可以訪問。例如:


/**
* @description 當(dāng)成員被標(biāo)記成 protected 時,只能在類及其子類中訪問,在此之外不能訪問
* @class Person
*/
class Person{
    protected name: string;
    constructor(theName: string){
        this.name = theName;
    }
}
class Staff extends Person{
    private dpt: string;
    constructor(name: string, dpt: string){
        super(name);
        this.dpt = dpt;
    }
    greet(){
        console.log(`Hello, my name is ${ this.name } and I work in ${ this.dpt }.`);
    }
}
let hand = new Staff("hanpi", "technology");
    hand.greet;
    // console.log(hand. name);  // error


readonly 修飾符

你可以使用 readonly關(guān)鍵字將屬性設(shè)置為只讀的,只讀屬性必須在聲明時或構(gòu)造函數(shù)里被初始化


/**
* @description readonly 修飾符
* @class Octopus
*/
class Octopus{
    readonly name: string;
    constructor(theName: string){
        this.name = theName;
    }
}
let octo = new Octopus("yaya");
// octo.name = "lala";   // error


參數(shù)屬性

參數(shù)屬性通過給構(gòu)造函數(shù)參數(shù)前面添加一個訪問限定符來聲明。 使用 private限定一個參數(shù)屬性會聲明并初始化一個私有成員;對于 public和 protected來說也是一樣

/**
* @description 參數(shù)屬性
* @class Octo
*/
class Octo{
    constructor(readonly name: string){ }
}
let a = new Octo("lala");


存取器

TypeScript支持通過getters/setters來截取對對象成員的訪問。 它能幫助你有效的控制對對象成員的訪問


let passcode = "secret passcode";
/**
* @description 存取器
* @class Employes
*/
class Employes{
    private _fullName: string = "lalala";
    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 Employes.");
        }
    }
}
let man = new Employes();
    console.log(man.fullName);
    man.fullName = "hahah";
    console.log(man.fullName);

對于存取器有下面幾點需要注意的:首先,存取器要求你將編譯器設(shè)置為輸出ECMAScript 5或更高。 不支持降級到ECMAScript 3。 其次,只帶有 get不帶有 set的存取器自動被推斷為 readonly。 這在從代碼生成 .d.ts文件時是有幫助的,因為利用這個屬性的用戶會看到不允許夠改變它的值。

靜態(tài)屬性

到目前為止,我們只討論了類的實例成員,那些僅當(dāng)類被實例化的時候才會被初始化的屬性。 我們也可以創(chuàng)建類的靜態(tài)成員,這些屬性存在于類本身上面而不是類的實例上


/**
* @description 靜態(tài)屬性, 類的靜態(tài)成員,這些屬性存在于類本身上面而不是類的實例上
* @class Grid
*/
class Grid{
    static origin= { x: 0, y: 0 };
    calculateDistance( point: { x: number, y: number }){
        let xDis = point.x - Grid.origin.x;
        let yDis = point.y - Grid.origin.y;
        return Math.sqrt(xDis*xDis + yDis*yDis) / this.scale;
    }
    constructor(public scale: number){}
}
let grid1 = new Grid(1);
console.log(grid1.calculateDistance({ x: 10, y: 10 }));


抽象類

抽象類做為其它派生類的基類使用。 它們一般不會直接被實例化。 不同于接口,抽象類可以包含成員的實現(xiàn)細節(jié)。 abstract關(guān)鍵字是用于定義抽象類和在抽象類內(nèi)部定義抽象方法


抽象類中的抽象方法不包含具體實現(xiàn)并且必須在派生類中實現(xiàn)


/**
* @description 抽象類
* @abstract
* @class A
*/
abstract class A{
    constructor(public name: string){};
    printName(): void{
        console.log(`Name is: ${ this.name }.`);
    }
    abstract printMeeting(): void; // 必須在派生類中實現(xiàn)
}

class B extends A{
    constructor(){
        super("Lyli");
    }
    printMeeting(): void{
        console.log("meeeting");
    }
    printHaha(): void{
        console.log("heihei..");
    }
}

let ah : A;
    // ah = new A(); // error, 無法創(chuàng)建抽象類的實例
    ah = new B();
    ah.printName();
    ah.printMeeting();
    // ah.printHaha(); // 方法在 A 上不存在

高級技巧

構(gòu)造函數(shù)

當(dāng)你在TypeScript里聲明了一個類的時候,實際上同時聲明了很多東西。 首先就是類的 實例的類型

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

let greeter: Greeter;
greeter = new Greeter("world");
console.log(greeter.greet());

這里,我們寫了 let greeter: Greeter,意思是 Greeter類的實例的類型是 Greeter。 這對于用過其它面向?qū)ο笳Z言的程序員來講已經(jīng)是老習(xí)慣了。


我們也創(chuàng)建了一個叫做 構(gòu)造函數(shù)的值。 這個函數(shù)會在我們使用 new創(chuàng)建類實例的時候被調(diào)用。 下面我們來看看,上面的代碼被編譯成JavaScript后是什么樣子的:


let Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();

let greeter;
greeter = new Greeter("world");
console.log(greeter.greet());

上面的代碼里, let Greeter將被賦值為構(gòu)造函數(shù)。 當(dāng)我們調(diào)用 new并執(zhí)行了這個函數(shù)后,便會得到一個類的實例。 這個構(gòu)造函數(shù)也包含了類的所有靜態(tài)屬性。 換個角度說,我們可以認為類具有 實例部分與 靜態(tài)部分這兩個部分。

把類當(dāng)接口使用

如上一節(jié)里所講的,類定義會創(chuàng)建兩個東西:類的實例類型和一個構(gòu)造函數(shù)。 因為類可以創(chuàng)建出類型,所以你能夠在允許使用接口的地方使用類


/**
* @description 把類當(dāng)接口使用
* @class Point
*/
class Point{
    x: number;
    y: number;
}
interface Ponit3d extends Point{
    z: number;
}
let point3d: Ponit3d = { x: 1, y: 2, z: 3 };

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容