TypeScript學(xué)習(xí)-Classes

介紹


傳統(tǒng)的JavaScript使用函數(shù)和基于原型的繼承來(lái)構(gòu)建可復(fù)用的組件,ES6引進(jìn)了基于類(lèi)的OO編程方法,TypeScript也是使用了最新的ES6語(yǔ)法進(jìn)行構(gòu)建的,它能將這些高級(jí)特性編譯成能在現(xiàn)代瀏覽器上運(yùn)行的JavaScript版本。


Classes特性

  • C#Java類(lèi)似,包括屬性、方法constructor(構(gòu)造函數(shù))

  • 成員訪問(wèn)符 this,我們?cè)陬?lèi)中用this語(yǔ)法訪問(wèn)類(lèi)中instance屬性

// eg
class Greeter {
    greeting: string;
    constructor(message: string) {
// this 成員訪問(wèn)符
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}
  • 通過(guò)new方法創(chuàng)建類(lèi)的instance,這將調(diào)用我們?cè)陬?lèi)中定義的constructor(構(gòu)造函數(shù)),它將完成兩件事: 創(chuàng)建一個(gè)和Greeter類(lèi)一樣Shape的新對(duì)象,然后通過(guò)constructor里面的語(yǔ)句Initialize實(shí)例屬性
let  greeter = new Greeter("world");
// 

繼承

  • 通過(guò)extends關(guān)鍵字來(lái)繼承父類(lèi)
class Animal {
      name: string;
      constructor(theName: string) { this.name =     theName; }
      move(distanceInMeters: number = 0) {
      console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}
// 繼承
class Horse extends Animal {}
  • 通過(guò)super關(guān)鍵字調(diào)用父類(lèi)(base class)的constructor
class Horse extends Animal {
  constructor(name: string) { super(name); }
    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}
  • 通過(guò)sub classbase class同名的方法,會(huì)重載(override)父類(lèi)的方法
class Horse extends Animal {
  constructor(name: string) { super(name); }
// move 重載 父類(lèi)的move方法
    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

訪問(wèn)修飾符

  • public 修飾符
    默認(rèn)設(shè)置為 public,不需要顯式的寫(xiě)出(C#等語(yǔ)言需要顯式寫(xiě)出),這樣無(wú)論在子類(lèi)中還是類(lèi)外都可以無(wú)限制訪問(wèn)base class中的屬性或方法
class Animal {
//此時(shí) public也可以不寫(xiě)
    public name: string;
    public constructor(theName: string) { this.name = theName; }
    public move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}
  • private 修飾符
    如果在屬性或方法前面設(shè)置了private,就不能在任何sub class或類(lèi)外訪問(wèn)到這個(gè)屬性或方法
class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}
new Animal("Cat").name; // Error: 'name' is private;

如果將base classconstructor加上private修飾符,那么派生類(lèi)也不不能調(diào)用super()方法訪問(wèn),類(lèi)外也不能實(shí)例化:

class Person {
    protected name: string;
    private constructor(theName: string) { this.name = theName; }
}
let john = new Person('John'); //Error, The constructor is private

TypeScript是一個(gè)基于結(jié)構(gòu)(shape)比較的類(lèi)型檢查系統(tǒng)(原文:是一種結(jié)構(gòu)類(lèi)型系統(tǒng),我為了更好的理解自作主張擴(kuò)充),也就是說(shuō):
如果類(lèi)中沒(méi)有privateprotected等修飾符,那么這個(gè)類(lèi)的成員和要檢查的類(lèi)型相同,那么它們兩類(lèi)型就是相同的。

class BigCar {
    name: string;
    constructor(theName: string) { this.name = theName; }
}
class SmallCar {
    name: string;
    constructor(theName: string) { this.name = theName; }
}
// 上面兩個(gè)類(lèi)是相同類(lèi)型的

反之,如果存在privateprotected那么除了檢查形狀(shape),還要檢查privateprotected后屬性或方法的申明源originated是否相同。
簡(jiǎn)而言之就是,它們的privateprotected后屬性或方法必須來(lái)源同一個(gè)申明。

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}
class Rhino extends Animal {
    constructor() { super("Rhino"); }
}
class Employee {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");
animal = rhino;
animal = employee; // Error: 'Animal' and 'Employee' are not compatible
  • protected修飾符
    除了能夠在(deriving classes)派生類(lèi),也就是子類(lèi)中訪問(wèn)到base class成員,其他的特性和private基本一致
class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }
}
class Employee extends Person {
    private department: string;
    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }
    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}
let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // error

如果給constructor加上protected修飾符,那么base class只能在派生類(lèi)中被super()調(diào)用,在類(lèi)外不能實(shí)例化。

class Person {
    protected name: string;
    protected constructor(theName: string) { this.name = theName; }
}
// Employee can extend Person
class Employee extends Person {
    private department: string;
    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }
    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}
let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: The 'Person' constructor is protected

只讀修飾符

  • readonly只能在定義時(shí)初始化,或者在constructor中初始化
class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.
  • 參數(shù)屬性:Parameter properties。由于定義readonly屬性和在constructor中初始化是一個(gè)很常用的屬性,所以TypeScript做了一個(gè)簡(jiǎn)化,讓你在constructor中的parameter list前面加上readonly修飾符,那么在調(diào)用constructor創(chuàng)建一個(gè)新類(lèi)并初始化的時(shí)候就能同時(shí)創(chuàng)建一個(gè)readonly成員屬性,并初始化,而不用寫(xiě)在兩個(gè)地方。
class Octopus {
    readonly numberOfLegs: number = 8;
    constructor(readonly name: string) {
    }
}
//實(shí)際上readonly、public、private、protected都能獲得以上的create and initialize的效果

訪問(wèn)器Accessors

  • TypeScript提供getters / setters方法,使得你能精細(xì)的控制怎么對(duì)成員進(jìn)行操作。
  • 通過(guò)攔截讀或?qū)懖僮?,?lái)避免不必要的bug
let passcode = "secret passcode";
class Employee {
    private _fullName: string;
    get fullName(): string {
        return this._fullName;
    }
    set fullName(newName: string) {
        if (passcode && passcode == "secret passcode") {
            this._fullName = newName;
        }
        else {
            console.log("Error: Unauthorized update of employee!");
        }
    }
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
    console.log(employee.fullName);
}
  • 只設(shè)置了get而沒(méi)有set那么這個(gè)屬性就是只讀的readonly
  • 只用ES5及以上的版本支持get / set

靜態(tài)屬性Static Properties

  • 類(lèi)其實(shí)包括兩個(gè)方面:instance sidestatic side,其中在屬性或方法前面加上了static以及constructorstatic side, 其余為 instance side
  • static 屬性通過(guò)類(lèi)名直接獲取,constructor通過(guò)new關(guān)鍵字創(chuàng)建實(shí)例
class Grid {
    static origin = {x: 0, y: 0};
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor (public scale: number) { }
}
let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

抽象類(lèi)Abstract classes

  • 抽象類(lèi)只能是基類(lèi),不是繼承自其它類(lèi)或抽象類(lèi)。只能被繼承。
  • 抽象類(lèi)不能直接實(shí)例化。
  • 相比Interface,抽象類(lèi)的成員可以包含具體的細(xì)節(jié),例如函數(shù)體的具體內(nèi)容。
  • 抽象類(lèi)中加了abstract關(guān)鍵字的省略了細(xì)節(jié),而且派生類(lèi)必須實(shí)現(xiàn)這些屬性。
  • 抽象類(lèi)中可以沒(méi)有抽象屬性
  • 有抽象屬性的類(lèi)一定是抽象類(lèi),必須帶上abstract關(guān)鍵字
abstract class Department {
    constructor(public name: string) {
    }
    printName(): void {
        console.log("Department name: " + this.name);
    }
    abstract printMeeting(): void; // must be implemented in derived classes
}
class AccountingDepartment extends Department {
    constructor() {
        super("Accounting and Auditing"); // constructors in derived classes must call super()
    }
    printMeeting(): void {
        console.log("The Accounting Department meets each Monday at 10am.");
    }
    generateReports(): void {
        console.log("Generating accounting reports...");
    }
}
let department: Department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type

高級(jí)技巧

  • 構(gòu)造函數(shù)Constructor functions
    當(dāng)在TypeScript定義了一個(gè)類(lèi)的時(shí)候,實(shí)際上創(chuàng)建了兩份申明。
  • 這個(gè)類(lèi)的實(shí)例類(lèi)型
  • 這個(gè)類(lèi)的構(gòu)造函數(shù)

也就是說(shuō),創(chuàng)建一個(gè)類(lèi),用類(lèi)名賦予類(lèi)型檢查的時(shí)候是相當(dāng)于一個(gè)包含了這個(gè)類(lèi)所有實(shí)例成員的一個(gè)Interface
而類(lèi)名賦予變量,則相當(dāng)于把這個(gè)類(lèi)的構(gòu)造函數(shù)賦值給一個(gè)變量,所以用類(lèi)型檢查要用typeof 類(lèi)名

class Greeter {
    static standardGreeting = "Hello, there";
    greeting: string;
    greet() {
        if (this.greeting) {
            return "Hello, " + this.greeting;
        }
        else {
            return Greeter.standardGreeting;
        }
    }
}
//用Greeter作為類(lèi)的實(shí)例的類(lèi)型來(lái)做類(lèi)型檢查
let greeter1: Greeter;
greeter1 = new Greeter();
console.log(greeter1.greet());
//typeof Greeter實(shí)際上類(lèi)的靜態(tài)屬性或方法的類(lèi)型來(lái)做類(lèi)型檢查
let greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = "Hey there!";
let greeter2: Greeter = new greeterMaker();
console.log(greeter2.greet());
  • 把類(lèi)當(dāng)做interface來(lái)用
    因?yàn)轭?lèi)名用作類(lèi)型檢查的作用和Interface類(lèi)似

綜上。接口可以繼承結(jié)構(gòu),結(jié)構(gòu)可以繼承類(lèi)。類(lèi)可以繼承類(lèi),類(lèi)可以實(shí)現(xiàn)接口。再加上一系列修飾符的限制,使得我們可以使用TypeScript完成很多豐富的操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,638評(píng)論 18 399
  • { "Unterminated string literal.": "未終止的字符串文本。", "Identifi...
    一粒沙隨風(fēng)飄搖閱讀 11,299評(píng)論 0 3
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,010評(píng)論 0 11
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • 我以吻回蒼天,卻被報(bào)以痛苦掙扎 1. 有多少人每天在抱怨自己生不逢時(shí),出生在一個(gè)地圖上也很難找到的無(wú)名小鎮(zhèn),而非大...
    不二檸檬閱讀 879評(píng)論 0 1

友情鏈接更多精彩內(nèi)容