TS簡明教程(2)——類與接口

爲了後續內容(如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
  1. 子類存在構造方法時,必須顯示調用父類構造方法先有父親,後有兒子
  2. TS方法調用是基於而不是基於類型聲明,好比child聲明爲Parent類型,可是值是子類型,因此調用方法時會調用子類say

訪問限定符

public

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

private

私有訪問,只能在本類訪問,子類和其餘類都不行spa

class Parent {
    private name: string;

    private say() {
        console.log(`say ${this.name}`);
    }
}
const p = new Parent();
p.name = 'hello'; // 錯誤,private限定的屬性不能被外部訪問
p.say(); // 錯誤,private限定的訪問不能被外部訪問

protected

保護性訪問,只能被本類或本類的子類(子類的子類也能夠訪問)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

在傳統語言中,幾乎不會直接聲明公有屬性,而後對其進行操做,都會先定義私有屬性,而後提供gettersetter方法對其操做(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有興趣的小夥伴能夠掃碼加我進行交流
微信

相關文章
相關標籤/搜索