天天看點

TypeScript:類(Classes)

傳統的Javascript關注的是函數(function)和基于原型(prototype-based)的繼承作為建構可重複使用元件的基本方式,但是與更舒服地使用面向對象的方式比較,這可能讓程式員感到有點難受了。在面向對象中,類繼承了功能, 然後對象從類中産生。從下一代版本的JS(ECMAScript6)開始,JS程式員可以使用基于類的面向對象的方式來建構應用。在TS中,我們允許程式員不用等待下一代JS出來,現在就使用這些技術,并且把它們向下編譯成可在所有主流浏覽器和平台上運作的JS。

先來看一個簡單的基于類的例子:

TypeScript:類(Classes)

var user = new Greeter("World!");

document.writeln(user.greet());

TypeScript:類(Classes)

如果你熟悉Java或者C#的話,那麼這段代碼對你而言很簡單。首先,聲明了一個類,該類有三個成員:包括一個屬性greeting,一個構造函數和一個方法greet。

你會發現,在我們使用類的某個成員時,是通過this關鍵字來通路的,這表明它是一個成員通路。

倒數第二行我們使用new關鍵字建立了一個Greeter類的對象,這會調用我們之前定義的構造函數,使用Greeter模型建立了一個新的對象,然後運作構造函數進行初始化。

在TS中,我們使用通用的面向對象模式。當然,在基于類的程式設計中,最基本模式之一就是使用繼承這一特征來擴充已存在的類來建立一個新類。

來看一個例子:

TypeScript:類(Classes)

var snakeObj = new Snake("眼鏡蛇");

var horseObj: Animal = new Horse("千裡馬");

snakeObj.move();

horseObj.move(1000);

TypeScript:類(Classes)

這個例子覆寫了TS中相當一部分繼承特征。我們這裡使用了extends關鍵字來建立一個子類。你可以看到Snake和Horse類都是Animal的子類,進而獲得了父類的通路權。

這個例子也說明了,如果子類需要,就可以重寫父類中的方法。例子中Snake和Horse類都建立了一個move方法,并且重寫了來自Animal的move方法,這樣就把父類的特有功能給了每個子類。

你可能已經注意到在上面的例子中,我們沒有使用關鍵字public就能使類的成員可見。像C#語言就必須要求每一個成員顯式地标明public才是可見的。在TS中,每一個成員預設都是public的。

你仍然可以把成員标記為private,目的是你可以控制它在你的類之外是公共可見的。我們可以這樣寫之前的Animal類:

TypeScript:類(Classes)
TypeScript:類(Classes)

TS是一個結構型系統。當比較兩個不同的類型時,不用考慮它們來自哪裡,如果它們的每一個成員的類型是相容的,那麼我們就說這兩個類型是相容的。

當比較具有private成員的類型時,我們就要具體分析了。對于兩個相容的類型而言,如果其中一個類有一個private成員,那麼另外一個必須要有一個産生自相同聲明的private成員(換言之,共用同一個聲明)。

來通過一個執行個體來更好地了解:

TypeScript:類(Classes)

class Employee {

private name: string;

constructor(theName: string) {

this.name = theName;

}

var animalObj = new Animal("公雞");

var snakeObj = new Snake("蛇");

var emloyeeObj = new Employee("雇員");

animalObj = snakeObj;

animalObj = emloyeeObj;//報錯,因為Employee類有name的私有聲明,不能把它複值給animalObj的name屬性

TypeScript:類(Classes)

在這個例子中,我們有三個類,其中”Snake”是Animal的子類。我們也建立了一個看上去和Animal樣子一樣的新類”Employee“。我們也建立了這些類的 執行個體,并把它們互相指派看會發生什麼。因為Animal和Snake共享同一個Animal中的聲明”private name:string“,是以它們是相容的。然而,這對Employee不是這樣。當嘗試将一個Employee對象指派給Animal時,會得到一個類型不相容的錯誤。雖然Employee也有一個名為name的私有成員,但是它和Animal中的那個私有成員不是同一個。

通過建立參數類型,public和private關鍵字也是建立和初始化類的成員快捷方式。該屬性能夠讓你一步建立和初始化一個成員。看下面我們修改之前例子的代碼。注意我們是如何不使用”theName“而在constructor上使用快捷的”private name:string”來建立并初始化name參數。

TypeScript:類(Classes)
TypeScript:類(Classes)

用這種方式使用private來建立和初始化一個private成員,對于public也是同樣的道理。

TS支援getters和setters作為通路一個對象成員攔截方式。這對于每個對象上的一個成員是如何被通路的提供了一種細粒度控制的方式。

下面使用get和set來轉換一個類。首先,先不使用setter和getter來開始這個例子。

TypeScript:類(Classes)
TypeScript:類(Classes)

雖然允許人們直接随意地設定fullName相當友善,但是如果人們突發奇想就可以改變名字,這會讓我們很困惑。

在下面這個版本中,我們允許使用者修改雇員之前,先要檢測確定使用者有一個有效的安全密碼。我們可以使用會檢測安全密碼的set來取代直接通路fullName。我們添加一個相應的get來允許之前的例子繼續無縫運作。

TypeScript:類(Classes)
TypeScript:類(Classes)

為了證明通路器現在正在檢查安全碼,我們可以修改安全碼來看當安全碼不比對的時候,會不會彈出一個對話框說“您沒有權限修改雇員資訊!”。

修改passcode為12345時,彈出錯誤提醒:

TypeScript:類(Classes)

注意:通路器要求你必須将編譯器設定為輸出ECMAScript 5。

說到這裡,我們目前隻讨論了類的執行個體成員,它們隻有當類執行個體化時才會出現在對象上。我們也可以建立靜态成員,它們對于類自身都是可見的而不是執行個體。下面的例子,我們在origin上使用了static關鍵字,因為它對于所有的grids都是通用的。每一個執行個體都可以通過附加的類名來通路這個值。和執行個體通路之前加上this關鍵字相似。

TypeScript:類(Classes)
TypeScript:類(Classes)

在TS中聲明一個類的時候,實際上是一次建立了多個聲明。第一個是執行個體類的類型。

TypeScript:類(Classes)

var user:Greeter;

TypeScript:類(Classes)

這裡,當我們聲明”var user:Greeter;”時,我們使用了Greeter作為Greeter類的執行個體的類型。這個對于來自面向對象語言的程式員來說幾乎是第二個特性。

我們也通過調用構造函數建立其他值。這個函數是在我們new出類的執行個體的時候調用的。為了了解實踐中它是什麼樣子,讓我們通過上面的TS代碼生成的JS代碼來看一下:

TypeScript:類(Classes)
TypeScript:類(Classes)

這裡,“var user”将會被構造函數指派。當我們調用new并運作這個函數的時候,我們得到了該類的一個執行個體。構造函數也包含了該類的所有靜态成員。思考每個類的另外一種方式是類有執行個體的一面和靜态的一面。

稍微修改一下例子看一下不同:

TypeScript:類(Classes)

var user: Greeter;

user = new Greeter();

alert(user.greet());

var greetMaker: typeof Greeter=Greeter;

greetMaker.standardGreeting = "Hey,there!";

var user2: Greeter = new greetMaker();

alert(user2.greet());

TypeScript:類(Classes)

這個例子中,“user”和之前運作相似。我們執行個體化Greeter類,然後使用了這個對象。這個之前已經看到過。

下一個,然後我們直接隻用類。這裡我們建立了一個新的變量叫做“greetMaker”。這個變量保持了類本身,或者說成是它的構造函數。這裡我們使用了typeof Greeter,意思是“給我們Greeter類本身的類型”而不是類型的執行個體。或者,更準确地說,“給我叫做Greeter的标志的類型”,它是構造函數的類型。這個類型包含了Greeter的所有的靜态成員和建立Greeter類執行個體的構造函數。

正如之前說的,一個類的聲明建立了兩樣東西:代表類的執行個體的類型和構造函數。因為類建立了類型,是以你可以在你可以使用接口的地方使用它們,例如:

TypeScript:類(Classes)

interface Point3D extends Point {

z: number;

var point3D: Point3D = { x: 1, y: 2, z: 3 };

TypeScript:類(Classes)

<a></a>

<a>本文轉自tkbSimplest部落格園部落格,原文連結:http://www.cnblogs.com/farb/p/TSClass.html,如需轉載請自行聯系原作者</a>

繼續閱讀