天天看點

JavaScript中的“類”

原文:JavaScript classes

    JavaScript是一種功能強大而優雅的語言,它擁有許多很好的特點,然而,有一個特點是它所不具備的,那就是“類”,至少在它的靜态類型上沒有經典繼承的語義。但是,JavaScript有一個健狀的對象原型(prototype)系統,這也是本文探讨的基礎。

    開始吧,考慮下面這個簡單的JavaScript函數:

function Person( name ){
	this.name = name;
}      

    從上面的代碼可以了解,在JavaScript中,函數除了發揮它們通常的作用外,還是JavaScript中原型(prototype)的基礎。我們可以使用如下代碼建立新的Person執行個體:

var bob = new Person( "Bob");
var alice = new Person( "Alice");      

   在這裡要指出的是,bob是一個從Person的原型中建立的對象。如果我們通路bob.name會發現它包含字元串“Bob”。bob對象擁有一些可用方法,像toString(),它們都是從Object中繼承而來的(稍後更多介紹)。

   與其它經典的靜态類型繼承語言(Java,C#)中的類不同,JavaScript中的原型(prototypes)是可以修改的,它的每個執行個體都會相應的應用這種改變。假設我們想要Person的所有執行個體都有一個greet()方法,可以用以下代碼達到目的:

Person.prototype.greet = function( otherPerson ){
	alert( "Hello " + otherPerson.name + ", I'am " + this.name );
}      

   現在我們有了兩個可以互相問候的Person,bob和alice:

bob.greet( alice ); // alerts "Hello Alice, I'm Bob"
alice.greet( bob ); // alerts "Hello Bob, I'm Alice"      

   當我們調用 bob.greet()方法時,JavaScript引擎會在下面的位置查找 greet 函數:

       1.bob自身的屬性(成員)(如同 bob.name)

       2.Person.prototype的屬性

       3.Object.prototype的屬性

   JavaScript引擎在找到作為Person.prototype屬性的greet後将不再查找,另外,如果調用 bob.toString()則會強制JavaScript引擎沿着上面的路徑向上查找,直到在Object.prototype中找到一個相比對的。我們也可以通過在Person.prototype中定義toString()重載其行為。

Person.prototype.toString = function(){
	return this.name.toString();
};      

    前面列出的三個位置是JavaScript運作時查找屬性的唯一地方,換句話說,在面向對象的語言中以建立父類的子類的方式來繼承,而JavaScript并不會天生的像這樣支援原型到原型的繼承。當然,JavaScript也足夠強大,它允許使用架構或庫以不同的形式來覆寫繼承模式。例如,一種方式,複制一個原型的成員到另一個原型,另一種進階些的方式,捕獲屬性查找事件,然後沿着一個特别維護的繼承鍊查找,傳回第一個比對的屬性。本文隻作介紹性的提及,這兩種方法都已經超出了本文的介紹範圍。

    本文将注意力完全集中在JavaScript中的“類”的入門上,我希望這裡的介紹能建立起一些概念,在将來的文章中再來深入剖析,如,關鍵字“new”的内部工作方式。

繼續閱讀