TypeScript躬行記(3)——類
類是對物件的抽象,描述了物件的特徵和行為,而物件就是類的例項。ES6引入了類的概念(相關內容可參考ES類和ES6類的繼承兩節),TypeScript在此基礎上,不僅根據ES7等規範完善了類的語法,還添加了許多其它語法。而在使用TypeScript的類時,不必關心相容性問題,因為這些工作已由編譯器完成。
下面是一個簡單的類,包含3個成員:帶private修飾符的name屬性、建構函式constructor()和getName()方法,最後一句使用new運算子建立了Person類的例項,並呼叫了一次它的建構函式。
class Person { private name: string; constructor(name: string) { this.name = name; } getName() { return this.name; } } let worker = new Person("strick");
編譯後的程式碼如下所示,通過傳統的建構函式和基於原型的繼承來模擬一個類。
var Person = /** @class */ (function() { function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; }; return Person; })(); var worker = new Person("strick");
一、屬性
在ES6中,例項屬性(即自有屬性)得作為this物件的屬性存在,並且一般都會在建構函式中執行初始化,而TypeScript允許在類中直接定義例項屬性,如下所示。
class Person { constructor(name: string) { this.name = name; } } //TypeScript中的例項屬性 class Person { name: string; }
不僅如此,TypeScript還提供了存在於類本身上的靜態屬性,即不需要例項化就能呼叫的屬性。在下面的示例中,為age屬性添加了static關鍵字,使其成為靜態屬性,通過類的名稱就能直接呼叫它。
class Person { static age: number; } Person.age = 28;
二、修飾符
修飾符是用於限定成員或型別的一種符號,TypeScript包含三個訪問修飾符:public、private和protected,以及一個成員修飾符:readonly。
1)public
在TypeScript中,成員預設都是public的,即在派生類(也叫子類)或類的外部都能被訪問。在下面的示例中,Person類中的name屬性是公共的,Programmer類繼承了Person類。注意,當派生類包含一個建構函式時,必須呼叫super()方法,執行基類(即父類)的建構函式,並且該方法得在訪問this物件之前呼叫。
class Person { public name: string; constructor(name: string) { this.name = name; } } class Programmer extends Person { constructor(name: string) { super(name); } }
在初始化Person類或Programmer類之後,就能通過建立的例項來訪問name屬性,如下所示。
let person = new Person("strick"); person.name; //"strick" let programmer = new Programmer("freedom"); programmer.name; //"freedom"
2)private
當成員被修飾為private時,只能在類的內部訪問它,例如在基類Person中宣告一個私有的age屬性,在類的例項或派生類的例項中訪問age屬性都會在編譯階段報錯,如下所示。
class Person { private age: number; } person.age; //錯誤 programmer.age; //錯誤
當建構函式被修飾為private時(如下所示),包含它的類既不能例項化,也不能被繼承。
class Person { private constructor(name: string) { this.name = name; } }
3)protected
此修飾符與private的行為類似,只是有一點不同,即在派生類中還是可以訪問它的,例如在基類Person中宣告一個受保護的school屬性,在派生類中就能訪問到它,如下所示(省略了基類的建構函式)。
class Person { protected school: string; } class Programmer extends Person { constructor(name: string) { super(name); this.school = "university"; } }
當建構函式被修飾為protected時(如下所示),包含它的類不能例項化,但可以被繼承。
class Person { protected constructor(name: string) { this.name = name; } }
4)readonly
當成員被修飾為readonly時,它就變成只讀的,只能在宣告時或建構函式裡初始化,其它地方對它的修改都是禁止的,如下所示。
class Person { readonly gender: string = "女"; //正確 constructor() { this.gender = "男"; //正確 } } let person = new Person(); person.gender = "女"; //錯誤
當readonly與其它修飾符一起使用時,需跟在它們後面,如下所示。
class Person { protected readonly gender: string; }
三、引數屬性
引數屬性可以便捷的在建構函式中宣告並初始化一個類的屬性,此類引數會與三個訪問修飾符或readonly組合使用,如下所示。
class Person { constructor(public name: string) { } }
建構函式中的name是一個引數屬性,相當於在Person類中宣告一個name屬性,並在建構函式中為其初始化,如下所示。
class Person { public name: string; constructor(name: string) { this.name = name; } }
四、抽象類
抽象類是供其它派生類繼承的基類,它與介面一樣,不能被例項化,但可以包含成員的實現細節。在宣告一個類時,如果包含abstract關鍵字,那麼這就是一個抽象類,如下所示,當對其進行例項化時,會在編譯時報錯。
abstract class Person { } let person = new Person(); //錯誤
在抽象類中,會宣告一個或多個帶abstract類修飾符的抽象方法,它們只有名稱,不包含實現細節,可與訪問修飾符組合使用,如下所示。
abstract class Person { protected abstract work(): void }
派生類中必須實現繼承的抽象方法(如下所示),否則會在編譯階段報錯。
class Programmer extends Person { public work(): void { console.log("code"); } }
&n