從C#到TypeScript - 類


總目錄

從C#到TypeScript - 類

在ES6之前Javascript的類都是用function定義的,ES6把類關鍵字正式加進來,雖說其實也還是function,不過代碼可讀性上好了不少。
TypeScript同樣支持class,並且和C#也非常相似,下面來看看:

同C#一樣,由構造函數,屬性,方法組成,屬性和方法有三個級別的訪問權限:private, protected, public,比C#少個internal
不過不同的是C#類的成員默認是private,而TypeScript默認是public
在類里面所有成員都必須用this來訪問。

class User{
    constructor(name: string, pwd: string){
        this.name = name;
        this.pwd = pwd;
    }

    name: string;
    private pwd: string;

    checkLogin(): boolean{
        return this.name === 'brook' && this.pwd === '123';
    }
}

let u: User = new User('brook', '123');
console.info(u.checkLogin()); // true

u.name = 'test';
console.info(u.checkLogin()); // false

參數屬性

上面的User類有兩個成員,而且都是從構造函數賦值的,也就是其實構造函數的參數就是類的成員,這就是參數屬性。
類里面的那兩個屬性其實可以不用寫,只要在構造函數的參數上加上操作限定符,TypeScript就會自動為參數生成屬性,來重構下上面的User

class User{
    constructor(public name: string, private pwd: string){ }

    checkLogin(): boolean{
        return this.name === 'brook' && this.pwd === '123';
    }
}

getter/setter

同樣,也有存取器,不過語法和C#不太一樣,寫起來稍麻煩些。
只有get的時候也就變成只讀屬性了。

class User{
    private _name: string;

    get name(): string{
        return this._name;
    }

    set name(name: string){
        this._name = name;
    }
}

靜態屬性和方法

上面說的都是實例成員,TypeScript也支持靜態成員,不用實例化,而是通過類名來訪問。

class User{
    static permission = 'user';

    static setPermission(p: string){
        User.permission = p;
    }
}

console.info(User.permission); // user

User.setPermission('admin');
console.info(User.permission); // admin

也同時支持staticreadonly,不過static要放在前面,這樣可以實現單例模式。

class User{
    
    static readonly instance = new User();

    private constructor(){}

    checkLogin(name: string, pwd: string): boolean{
        return name === 'brook' && pwd === '123';
    }
}

console.info(User.instance.checkLogin('brook', '123'));

抽象類

這點和C#一樣,都可以用抽象類來把有共同行為抽象出來,關鍵字都是abstract
不能實例化,可以包含實現,abstract標識的方法,繼承類必須實現。
但沒有virtual關鍵字,不過和Java一樣,可以認為是天生虛函數,也不需要override,直接覆蓋也能支持多態。
繼承類里要調用父類的函數需要用super關鍵字。

abstract class User{
    name: string;
    pwd: string;

    abstract checkLogin(): boolean;
    
    checkName(): boolean {
        return this.name.indexOf('.') < 0;
    }
}

class Admin extends User {
    checkLogin(): boolean {  // 必須實現的抽象方法
        return this.checkName();  
    }

    checkName(): boolean {  // 這里會把User里的checkName覆蓋掉
        return true && super.checkName();
    }
}

let user: User;
user = new Admin(); 
user.name = 'brook.shi';
console.info(user.checkLogin()); // 同樣有多態,checkLogin里調用的是Admin的checkName

另外,繼承時還需要注意,如果派生類里有構造函數,則構造函數必須要調用父類的構造函數:super()

兼容性

TypeScript里的類是有兼容性的,這點和C#很不一樣,TypeScript認為:只有成員的類型是兼容的,那它們的類型也是兼容的。
不過成員的兼容對於public很寬容,完全不相干的類如果全是public的成員,並且一致就認為是兼容的。
但對於privateprotected則只有是繼承的才會被認可為兼容。

class Test1{
    name: string;
    pwd: string;

    checkName(): boolean{
        return true;
    }
}


class Test2{
    name: string;
    pwd: string;

    checkName(): boolean{
        return false;
    }
}

let t: Test1 = new Test2();
console.info(t.checkName());  // false

如果給上面的TestTest2各加一個private email: string;,結果是編譯不了,因為它們並不是繼承關系,也就兼容不了。

泛型

同接口一樣支持泛型,用法也一樣,可以參考接口泛型。

interface Testable<T> {
    field: T;
    method(arg: T): T;
}

class Test<T> implements Testable<T>{
    field: T;
    method(arg: T): T{
        console.info(`arg is ${typeof arg}`);
        return null;
    }
}

let test11 = new Test<string>();
test11.method('method');  // arg is string
test11.method(123); // error, 123 is not string

總的來說,TypeScript的類和C#或Java可以說十分相似,除了兼容性基本上沒有什么新的東西,不過對於JavaScript來說卻是一大進步了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM