溫故知新——JS中創建對象或類的方法


提要

1、原始方式

2、工廠方式

3、構造方式

4、原型方式

5、構造原型混合方式

6、動態原型方式

7、混合工廠方式

目前使用最廣泛的是混合的構造函數/原型方式。此外動態原型方法也很流行在功能上與構造函數/原型方式等價。可以採用這兩種方式中的任何一種。不過不要單獨使用經典的構造函數或原型方式因爲這樣會給代碼引入問題。

1、原始方式

var oCar = new Object;
oCar.color = "blue";
oCar.doors = 4;
oCar.mpg = 25;
oCar.showColor = function() {
  alert(this.color);
};

缺點可能需要創建多個 car 的實例。


2、工廠方式

1使用工廠函數

function createCar() {
  var oTempCar = new Object;
  oTempCar.color = "blue";
  oTempCar.doors = 4;
  oTempCar.mpg = 25;
  oTempCar.showColor = function() {
    alert(this.color);
  };
  return oTempCar;
}

var oCar1 = createCar();
var oCar2 = createCar();

2使用帶參數的工廠函數

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("blue",3,25);

oCar1.showColor();		//輸出 "red"oCar2.showColor();		//輸出 "blue"


3在工廠函數外定義對象的方法

雖然 ECMAScript 越來越正式化但創建對象的方法卻被置之不理且其規範化至今還遭人反對。一部分是語義上的原因它看起來不像使用帶有構造函數 new 運算符那麼正規一部分是功能上的原因。功能原因在於用這種方式必須創建對象的方法。前面的例子中每次調用函數 createCar()都要創建新函數 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("blue",3,25);

oCar1.showColor();		//輸出 "red"oCar2.showColor();		//輸出 "blue"


在上面這段重寫的代碼中在函數 createCar() 之前定義了函數 showColor()。在 createCar() 內部賦予對象一個指向已經存在的 showColor() 函數的指針。從功能上講這樣解決了重複創建函數對象的問題但是從語義上講該函數不太像是對象的方法。

所有這些問題都引發了開發者定義的構造函數的出現。


3、構造函數方式

創建構造函數就像創建工廠函數一樣容易。第一步選擇類名即構造函數的名字。根據慣例這個名字的首字母大寫以使它與首字母通常是小寫的變量名分開。除了這點不同構造函數看起來很像工廠函數。請考慮下面的例子

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("blue",3,25);

與工廠函數相似也可以用外部函數重寫構造函數。


4、原型方式

該方式利用了對象的 prototype 屬性可以把它看成創建新對象所依賴的原型。

這裏首先用空構造函數來設置類名。然後所有的屬性和方法都被直接賦予 prototype 屬性。我們重寫了前面的例子代碼如下

function Car() {
}

Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();


注1使用這種方式還能用 instanceof 運算符檢查給定變量指向的對象的類型。因此下面的代碼將輸出 TRUE

alert(oCar1 instanceof Car);	//輸出 "true"

注2原型方式不能帶參數。

注3真正的問題出現在屬性指向的是對象而不是函數時。函數共享不會造成問題但對象卻很少被多個實例共享

function Car() {
}

Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;Car.prototype.drivers = new Array("Mike","John");Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();oCar1.drivers.push("Bill");alert(oCar1.drivers);	//輸出 "Mike,John,Bill"alert(oCar2.drivers);	//輸出 "Mike,John,Bill"


5、混合的構造函數/原型方式

聯合使用構造函數和原型方式就可像用其他程序設計語言一樣創建對象。這種概念非常簡單即用構造函數定義對象的所有非函數屬性用原型方式定義對象的函數屬性方法。結果是所有函數都只創建一次而每個對象都具有自己的對象屬性實例。

我們重寫了前面的例子代碼如下

function Car(sColor,iDoors,iMpg) {
  this.color = sColor;
  this.doors = iDoors;
  this.mpg = iMpg;
  this.drivers = new Array("Mike","John");
}

Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);

oCar1.drivers.push("Bill");

alert(oCar1.drivers);	//輸出 "Mike,John,Bill"alert(oCar2.drivers);	//輸出 "Mike,John"

所有的非函數屬性都在構造函數中創建意味着又能夠用構造函數的參數賦予屬性默認值了。

      因爲只創建 showColor() 函數的一個實例所以沒有內存浪費。

     此外給 oCar1 的 drivers 數組添加 "Bill" 值不會影響到 oCar2 的數組所以輸出這些數組的值時oCar1.drivers 顯示的是 "Mike,John,Bill"而 oCar2.drivers 顯示的是 "Mike,John"。

      因爲使用了原型方式所以仍然能利用 instanceof 運算符來判斷對象的類型。



6、動態原型方法

動態原型方法的基本想法與混合的構造函數/原型方式相同即在構造函數內定義非函數屬性而函數屬性則利用原型屬性定義。唯一的區別是賦予對象方法的位置。下面是用動態原型方法重寫的 Car 類

function Car(sColor,iDoors,iMpg) {
  this.color = sColor;
  this.doors = iDoors;
  this.mpg = iMpg;
  this.drivers = new Array("Mike","John");
  
  if (typeof Car._initialized == "undefined") {
    Car.prototype.showColor = function() {
      alert(this.color);
    };	
    Car._initialized = true;
  }
}


7、混合工廠方式

這種方式通常是在不能應用前一種方式時的變通方法。它的目的是創建假構造函數只返回另一種對象的新實例。

這段代碼看起來與工廠函數非常相似

function Car() {  

  oTempCar.color = "blue";
  oTempCar.doors = 4;
  oTempCar.mpg = 25;
  oTempCar.showColor = function() {
    alert(this.color);
  };

  return oTempCar;
}

由於在 Car() 構造函數內部調用了 new 運算符所以將忽略第二個 new 運算符位於構造函數之外在構造函數內部創建的對象被傳遞迴變量 car。

這種方式在對象方法的內部管理方面與經典方式有着相同的問題。強烈建議除非萬不得已還是避免使用這種方式。


參考文獻

http://www.w3school.com.cn/js/pro_js_object_defining.asp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章