關於javascript中類的繼承可以參考阮一峰的Blog《Javascript繼承機制的設計思想》,說的很透。
一、在javascript中執行個體化遇到的問題:
下面用《javascript進階程式設計》中的例子來做說明,假如現在定義了一個car的對象,它是Object類的執行個體。像下面這樣的:
複製代碼 代碼如下:var oCar=new Object();
oCar.color = "red";
oCar.doors = 4;
oCar.mpg = 23;
oCar.showColor = function () {
alert(this.color);
};
現在又需要這樣的一個執行個體,你可能會像這樣來定義: 複製代碼 代碼如下:var oCar2 = new Object();
oCar2.color = "blue";
oCar2.doors = 5;
oCar2.mpg = 25;
oCar2.showColor = function () {
alert(this.color);
};
這樣遇到的問題是每個對象都需要重新定義一次他的欄位和方法。很麻煩。
二、類的定義--工廠方式實現:
對上面的例子進行一個封裝,利用函數的傳回值來做文章: 複製代碼 代碼如下:function createCar() {
var oTempCar = new Object();
oTempCar.color = "red";
oTempCar.doors = 4;
oTempCar.mpg = 23;
oTempCar.showColor = function () {
alert(this.color);
};
return oTempCar;
}
調用方式:
var oCar1 = createCar();
var oCar2 = createCar();
這種方式被稱之為工廠方式。工廠方式看起來是省事多了。起碼建立一個對象的時候不再需要那麼多的行數。因為每個屬性(color,doors,mpg)的值都是固定的,還需要再次進行改造,利用參數傳遞來實現: 複製代碼 代碼如下:function createCar(sColor, iDoors, iMpg) {
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = function () {
alert(this.color);
};
return oTempCar;
}
var oCar1 = createCar("red", 4, 23);
var oCar2 = createCar("red", 4, 23);
oCar1.showColor();
oCar2.showColor();
這樣做看似的確可以實現了對象了。實現也很簡單,調用也很方便。但是有兩個不是很好的地方:
1、從語義上看,在建立對象時沒有使用new運算子,似乎不是那麼正規(通常建立一個對象都用一個new運算子來實現)。
2、不符合物件導向的特徵--封裝。在這個例子中,oCar1和oCar2都有自己的showColor方法,並且他們的showColor都是自己的實現。但是事實是他們共用的是同一個函數。
也是有辦法解決這個共用函數的問題,利用函數指標來解決。在createCar函數之外再建立一個showColor函數,而oTempCar的showColor方法指向這個showColor函數: 複製代碼 代碼如下:function showColor() {
alert(this.color);
}
function createCar(sColor, iDoors, iMpg) {
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = showColor;
return oTempCar;
}
var oCar1 = createCar("red", 4, 23);
var oCar2 = createCar("red", 4, 23);
oCar1.showColor();
oCar2.showColor();
雖然這樣解決了重複建立函數的問題,但這樣的話,就使showColor函數看起來不像是對象的方法。
三、類的定義--建構函式方式實現: 複製代碼 代碼如下:function Car(sColor, iDoors, iMpg) {
//通過建構函式的形式,會為每個對象產生獨立的屬性和函數
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function () {
alert(this.color);
};
}
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("red", 4, 23);
oCar1.showColor();
oCar2.showColor();
在Car類中,this指標代表了Car的一個執行個體,因此不需要傳回值。雖然建構函式方式實現了類的定義,但是和工廠方式一樣,他也是為每個執行個體建立一個單獨的方法。雖然可以像工廠函數一樣在函數之外再建立一個函數利用指標來解決這個問題,但是這麼做的話,在語義上沒有意義。
四、類的定義--原型方式實現:
利用對象的prototype屬性,把它看成是建立新對象所依賴的原型。用空建構函式來設定類名。然後所有的屬性和方法都被直接賦予prototype屬性。 複製代碼 代碼如下:function Car() {
}
Car.prototype.color = "red";
Car.prototype.doors = 4;
Car.prototype.mpg = 23;
Car.prototype.showColor = function () {
alert(this.color);
};
var oCar1 = new Car();
var oCar2 = new Car();
alert(oCar1 instanceof Car);//output true這裡存在兩個問題:
1、建構函式沒有參數。使用原型時,不能通過給函數參數傳遞參數來初始化屬性值。
2、在有多個執行個體時,對其中一個執行個體的屬性的更改會影響到另外一個執行個體的屬性。
測試代碼: 複製代碼 代碼如下:var oCar1 = new Car();
oCar1.color = "Green";
var oCar2 = new Car();
oCar2.color = "Black";
alert(oCar1.color); //output Green
alert(oCar2.color); //output Black
alert(oCar1.color); //output Black
當然了,也會有辦法解決這個問題的。那就是混合的建構函式/原型方式
五、類的實現--混合的建構函式/原型方式實現
這種實現方式是將每個類的執行個體中共用的屬性或者方法妨到原型鏈中實現,而將不需要共用實現的屬性和方法放在建構函式中實現。這中類的實現方式是使用最廣泛的方式。 複製代碼 代碼如下:function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike", "Sue");
}
Car.prototype.showColor = function () {
alert(this.color);
};
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("blue", 3, 24);
oCar1.drivers.push("Matt");
alert(oCar1.drivers);
alert(oCar2.drivers);六、類的定義--動態原型方式實現
這種方式和混合的建構函式/原型方式相比,提供了一種友好的編程風格(在混合的建構函式/原型方式中,showColor方法的定義是在方法體外實現的,而不是在建構函式的方法體內完成的)。這種類的定義方式使用也很多。 複製代碼 代碼如下:function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.divers = new Array("Mike", "Sue");
if (typeof Car._initialized == "undefined") {
Car.prototype.showColor = function () {
alert(this.color);
};
Car._initialized = true;
}
七、類的定義--混合工廠方式實現 複製代碼 代碼如下:function Car() {
var oTempCar = new Object();
oTempCar.color = "red";
oTempCar.doors = 4;
oTempCar.mpg = 23;
oTempCar.showColor = function () {
alert(this.color);
};
return oTempCar;
}
var car = new Car();
car.showColor();
這種方式和工廠方式看起來差不多。由於在Car()建構函式內部調用了new運算子,所以將忽略掉位於建構函式之外的new運算子。在建構函式內部建立的對象被傳回變數var。雖然看起來有了new運算子了,比工廠方式有了一些進步,但是這種實現方式也是會出現重複建立方法的問題。因此也不推薦使用這種方式來定義類。