爲了後續內容(如nestjs
等框架)的開展,本文更新TS相關的基礎知識。typescript
關注獲取更多TS精品文章
緩存
傳統JS使用函數
和原型鏈
進行集成,在ES6
出現了class
關鍵,JS也能使用傳統OOP的方式進行繼承,可是仍是存在必定的侷限性,在TS中,OOP已經和傳統語言差很少。微信
class Parent { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } say() { return `name: ${this.name}, age: ${this.age}`; } } const parent = new Parent(); parent.say();
能夠看到TS的OOP寫法和Java仍是有點相似的。可是他兩的構造方法名不一樣,TS構造方法名爲constructor
,Java是類名
。框架
繼承用來擴展示有的類,TS中這一點和傳統語言同樣使用extends
語法。函數
class Parent { name: string; constructor(name: string) { this.name = name; } say() { console.log(`Parent say: ${this.name}`); } } class Child extends Parent { age: number; constructor(name: string, age: number) { // 覆蓋父類構造方法 super(name); // 調用父類構造方法 this.age = age; } say() { console.log(`Child say: ${this.name} ${this.age}`); } } const child: Parent = new Child("haha" ,1); child.say(); // 輸出 Child say haha 1
顯示調用
父類構造方法先有父親,後有兒子
值
而不是基於類型聲明
,好比child
聲明爲Parent
類型,可是值是子類型,因此調用方法時會調用子類
的say
TS中方法和屬性默認的訪問限定符爲public
,全部外部或內部成員均可訪問。this
class Parent { public name: string; // public能夠不加 say() { console.log(`say ${this.name}`); } } const p = new Parent(); p.name = 'hello'; p.say(); // 輸出 say hello
私有訪問,只能在本類
訪問,子類和其餘類都不行
。spa
class Parent { private name: string; private say() { console.log(`say ${this.name}`); } } const p = new Parent(); p.name = 'hello'; // 錯誤,private限定的屬性不能被外部訪問 p.say(); // 錯誤,private限定的訪問不能被外部訪問
保護性訪問,只能被本類或本類的子類(子類的子類也能夠訪問)
。code
class Parent { protected name: string; constructor(name: string) { this.name = name; } protected say() { console.log(`say ${this.name}`); } } class Child extends Parent { public say() { // 提高訪問性 console.log(`say ${this.name}`); // 訪問父類屬性 } } const c = new Child('hello'); c.say(); // 輸出 say hello
訪問限定符只能提高,不能下降,以下例子是沒法經過編譯的
:對象
class Parent { protected name: string; } class Child extends Parent { private name: string; // 錯誤,子類訪問性必須>=父類的訪問性 }
TS使用readonly
聲明只讀屬性(方法不能使用)
,必須在聲明時
或者構造時
進行賦值,其餘地方不能賦值
繼承
class Parent { private readonly name = 'hello'; private readonly age: number; constructor(age: number) { this.age = age; } }
在上例中咱們在構造方法中使用this.age = age
對已存在的私有隻讀屬性age
進行了賦值。因爲該操做時經常使用操做,因此TS有了更加便捷的寫法:
class Parent { constructor(readonly name: string, private readonly age: number) { } say() { console.log(`say ${this.name} ${this.age}`); } }
上例中聲明瞭公有隻讀的name屬性,私有隻讀的age屬性
在傳統語言中,幾乎不會直接聲明公有屬性,而後對其進行操做,都會先定義私有屬性,而後提供getter
和setter
方法對其操做(Java中不少類都是這種狀況
)
class Parent { private _name: string; get name(): string { return this._name; } set name(name: string) { console.log(`name設置前: ${this._name} 設置後: ${name}`); this._name = name; } } const parent = new Parent(); parent.name = 'ok'; // 能夠直接使用賦值語句,可是會自動調用set name(name: string)方法
getter和setter方法提升了開發者對屬性的控制,一塊兒對屬性的訪問都是可控的,爲之後的擴展性打下了基礎(好比若是須要加緩存,咱們能夠在set時設置緩存,get時讀取緩存,若是是直接操做屬性的話,該功能實現起來很麻煩
以上討論的都是實例屬性和梳理方法
,須要有實例才能調用,若是有些屬性或方法並非存在於實例上時可使用靜態方法或靜態屬性
class Parent { static name: string; static say() { console.log(`name ${this.name}`); // 方法是靜態,屬性是靜態時可使用this } } Parent.say();// 使用類名調用靜態方法
須要注意的是實例能夠直接調用靜態,靜態不能直接調用實例
,由於實例須要實例化後調用
傳統語言中接口只包含實現,不包含細節。而抽象類能夠包含細節。通常來講,有些公有方法能夠放到抽象類作,不一樣的子類完成不一樣功能的代碼能夠放到抽象類作。
abstract class Animal { abstract say(): void; // 聲明抽象方法,子類必須實現 eat() { console.log(`animal eat`); } } class Human extends Animal { // 使用extends關鍵字 say() { console.log('human say words'); } } class Dog extends Animal { say() { console.log('dog say wangwang'); } }
接口用來限定子類的行爲,不關心具體實現。與傳統語言不一樣的是,TS接口還能夠限定變量或常量的屬性
限定子類行文:
interface Animal { say(): void; eat(): void; } class Human implements Animal { say() { console.log('human say'); } eat() { console.log('human eat'); } }
限定變量屬性:
interface A { name?: string; age: number; } const obj: A = { age: 10, // name是可選的 };
使用可索引類型
來描述
能夠經過索引訪問獲得
的類型。如person["name"]
,list[0]
interface HashMap { [key: string]: any; // 冒號左邊爲屬性名類型,右邊爲值類型 } const map: HashMap = {}; map["name"] = "1"; map.a = "2";
與類繼承相似,接口也能夠經過繼承來擴展示有的功能:
interface Animal { eat(): void; // 動物會吃,可是怎麼吃的無論 } interface Human extends Animal { say(): void; // 人會說話,可是怎麼說,說什麼無論 }
JS中,函數能夠直接調用也能夠經過對象方式調用,TS中能夠經過接口聲明被修飾的函數支持的調用方式:
interface Counter { (start: number): string; step: number; reset(): void; } function getCounter(): Counter { const counter = <Counter> function(start: number) {}; counter.step = 1; counter.reset = function() {}; } const c = getCounter(); c(1); c.reset(); c.step = 2;
面向對象中的類和接口內容實在是太多了,本文只選擇了開發中經常使用到的用法進行說明,不足之處,敬請包涵。
對TS有興趣的小夥伴能夠掃碼加我進行交流