TS學習筆記(三):類
傳統的 JavaScript 程式使用函式和基於原型的繼承來建立可重用的元件,從 ES6 開始,JavaScript 程式能夠使用基於類的面向物件的方式。使用 TypeScript,你可以使用 ES6 中規定的新特性,編譯後的 JavaScript 可以在所有主流瀏覽器和平臺上執行。
基本用法
class Person { public love: string; constructor(love: string) { this.love = love; } public sayLove() { console.log(`my love is ${this.love}`) } } 複製程式碼
繼承
在構造器裡訪問 this 的屬性之前,一定要呼叫super() ,這個是 TypeScript 強制執行的一條重要規則。
class Person { public love: string; constructor(love: string) { this.love = love; } public sayLove() { console.log(`my love is ${this.love}`) } } class SuperPerson extends Person { public name: string; constructor(love: string, name: string) { super(love); this.name = name; } public sayName(){ console.log(`my name is ${this.name}`) } } let me = new SuperPerson('HTML', 'funlee'); me.sayLove() me.sayName() 複製程式碼
訪問控制
public、private、protected
預設是 public, 不再贅述,參考前面例子。
當成員標記為 private 時,它就不能在宣告它的類的外部訪問,用 protected 修飾的屬性依然如此。
class Person { private love: string; // orprot constructor(love: string) { this.love = love; } public sayLove() { console.log(`my love is ${this.love}`) } } let me = new Person('TS'); me.love = 'JS'; // error 複製程式碼
private 和 protected 有一點不同, protected 成員在派生類中仍然可以訪問。例如:
class Person { protected name: string; constructor(name: string) { this.name = name; } } class Man extends Person { private love: string; constructor(name: string, love: string) { super(name); this.love = love; } public say() { // 如果Person 中用 private 修飾 name 則不能訪問到 name 屬性 console.log(`my name is ${this.name}, and my love is ${this.love}`); } } let me = new Man('funlee', 'TS'); 複製程式碼
注意:TypeScript 使用的是結構性型別系統,所以當比較兩種不同的型別時,如果所有的成員的型別都是相容的,那麼這兩個型別就是相容的。如:
class A { prop1: string } class B { prop1: string prop2: string } let instance:A = new B() // 允許這麼做,因為A的所有成員型別,B中都有 複製程式碼
但是如果被比較的類裡面含有 private 和 protected 型別成員的時候,情況就不同了,這時候需要另一個類裡也含有相應的 private 或 protected 成員,型別才能是相容的,所以有:
class A { private prop1: string } class B { private prop2: string } let p1:A = new B() // 報錯 class C extends A { } let p2:A = new C() // 允許這麼做 複製程式碼
readonly
可以使用 readonly 關鍵字將屬性設定為只讀的,只讀屬性必須在宣告時或建構函式裡被初始化。
class Person { readonly name: string; constructor(name: string) { this.name = name; } } let me = new Person('funlee'); me.name = 'new name'; // error 複製程式碼
引數屬性
引數屬性允許同時建立 和初始化成員 ,可以把宣告和賦值合併至一處,如:
class Person { constructor(public name: string, protected love: string, readonly age: number, private weight: string) { this.name = name; this.love = love; this.age = age; } public sayWeight() { console.log(`my weight is ${this.weight}`) } } let me = new Person('funlee', 'TS', 18, '55kg'); me.sayWeight() 複製程式碼
存取器
TypeScript 支援 getter 和 setter,但是有一點限制:編譯器輸出必須設為 ES5 或者更高,不支援降級到 ES3,另外,當一個存取器只帶有 get 卻不帶有 set 時,它會被自動推斷為 readonly。
class Person { public _love: string; constructor(love: string) { this._love = love; } get love(): string{ return this._love; } set love(newLove: string) { this._love = `error!! my love can't be chenged`; } } let me = new Person('TS'); console.log(me.love); // TS me.love = 'HTML'; console.log(me.love); // error!! my love can't be chenged 複製程式碼
靜態屬性
可以使用static來定義類裡的靜態屬性,靜態屬性屬於類自身,而不屬於例項,訪問的時候要用類名訪問,而不能用例項物件訪問,如:
class Person { static love: string = 'TS'; } let me = new Person(); console.log(Person.love); // TS console.log(me.love); // error 複製程式碼
抽象類
抽象類只能作為其他派生類的基類使用,抽象類不能被例項化,它具有如下特點:
- 抽象類可以包含成員的實現細節,且抽象類必須用 abstract 宣告
- 抽象類裡不含方法體的方法稱為抽象方法,使用 abstract 宣告,抽象方法必須被子類實現(抽象方法必須使用 abstract 關鍵字宣告,且可以包含訪問修飾符)
abstract class Person { public love: string; constructor(love: string) { this.love = love; } abstract sayLove(): string; // 必須在派生類中實現 } class Man extends Person{ constructor(love: string){ super(love) } sayLove() { return `my love is ${this.love}`; } } let me = new Man('TS'); console.log(me.sayLove()); // my love is TS 複製程式碼
把類當做介面使用
類定義會建立兩個東西:類的例項型別和一個建構函式,因為類可以創建出型別,所以能夠在允許使用介面的地方使用類。
class Person { name: string; age: number; } interface Man extends Person { love: string; } let me: Man = { name: 'funlee', age: 18, love: 'TS' } 複製程式碼