最近在閱讀《 JavaScript 進階程式設計》,未免遺忘讀過的內容,就打算以部落格的形式做些讀書筆記。今天介紹的是 JavaScript 中的四種定義對象的方法,除了這四種方法,還有Factory 方法來定義對象,但考慮到其簡單性及非正規性,這裡就不做介紹。和 Java 這樣的物件導向語言相比, JavaScript 更像是函數式語言,其並沒有類的概念,蓋之以對象定義的概念,而具體建立的對象叫做對象的執行個體。
1)建構函式方式定義對象。 這種方式是在建構函式內定義屬性和方法。這裡舉個簡單的例子:
function Animal(name){
this.name = name;
this.introduceSelf = function(){
window.alert("I am a " + this.name+"!");
};
}
對象的執行個體化如下:var dog = new Animal("dog");
dog. introduceSelf();
當然, 也可以將對象的方法在建構函式外定義,如下所示:function introduceSelf(){
window.alert("I am a " + this.name+"!");
}
function Animal(name){
this.name = name;
this.introduceSelf = introduceSelf();
}
這種在建構函式內定義所有的屬性和方法的方式,使得建構函式相當於 Java 中類的概念。而將方法的具體定義獨立地放在建構函式外,會使得對象的定義和方法的定義並不緊密,如果在一個檔案中這樣的方法和對象定義多的話,就會看起來淩亂許多。
2) 原型方式。 該方式利用對象的 prototype 屬性,可以將其看成建立新對象所依賴的原型(關於 prototype 的詳細資料,可以百度一下,這方面的資料還是很多的)。這種方式將建構函式做成空建構函式,然後將所有的屬性和方法被直接賦予 prototype 屬性,還是前面的例子,重寫如下:
function Animal(){
}
Animal.prototype.name = "animal";
Animal.prototype.introduceSelf = function(){
window.alert("I am a " + this.name+"!");
};
//對象的執行個體如下:
var dog = new Animal();
dog.name = "dog";
dog.introductSelf();
這種方式的缺點是顯而易見的,就是不能在建構函式中對屬性進行賦值操作。還有一點是,對於參考型別的屬性(如 Array 執行個體),執行個體化的多個對象將共用一個引用。正因為這麼多的問題,這種對象定義的方式並不可取。
3) 建構函式、原型混合方式。 這種方式是最為流行的對象定義方式。它結合了建構函式及原型方式。這種方式用建構函式定義對象的所有非函數屬性,用原型方式定義對象的函數屬性(方法)。重寫前面的例子:function Animal(name){
this.name = name;
}
Animal.prototype.introduceSelf = function(){
window.alert("I am a " + this.name+"!");
};
4) 動態原型方式。 和建構函式、原型混合方式相比,動態原型方式只是在函數屬性定義的位置上有所不同。重寫前面的例子:
function Animal(name){
this .name = name;
if ( typeof Animal._initialized == 'undefined'){
Animal.prototype.introduceSelf = function (){
window.alert( " I am a " + this .name + " ! " );
};
Animal._initialized = true ;
}
}
其中_initialized是Animal的全域私人屬性(JavaScript中沒有私人屬性的概念,所有的屬性都是共有的,但為了表明一些屬性的私人特性,人們習慣在屬性名稱前加上“_”。),當第一次執行個體化Animal時,if條件就為真,這樣就會定義Animal中的函數屬性。由於“Animal._initialized = true;”的存在,函數的定義調用一次而無論執行個體化多少個對象。