JavaScript之定義類或對象六種方式

1、工廠方式

     //類的定義

    function createCar(){
                 var oTempCar = new Object;
                 oTempCar.color = 'red';
                 oTempCar.doors = 4;
                 oTempCar.mpg = 23; //時速
                 oTempCar.showColor = function(){
                 alert(this.color);
        };
        return oTempCar;
    }

    //對象創建
    var car1 = new createCar();
    var car2 = new createCar();

    //也可以定義帶參數的類
    function createCar(iColor, iDoors, iMpg){
                 var oTempCar = new Object;
                 oTempCar.color = iColor;
                 oTempCar.doors = iDoors;
                 oTempCar.mpg = iMpg; //時速
                 oTempCar.showColor = function(){
                 alert(this.color);
        };
        return oTempCar;
    }

    //對象創建
    var car1 = new createCar('red', 4, 23);
    var car2 = new createCar('blue', 3, 25);
         前面的例子中,每次調用函數createCar(),都要闖建新函數showColor(),意味着每個對象都有自己的showColor()版本,事實上,每個對象都共享了同一個函數。爲了避開此問題,可以採用在工廠函數外定義對象的方法;

    function showColor(){
        alert(this.color);
    };

    function createCar(iColor, iDoors, iMpg){
                 var oTempCar = new Object;
                 oTempCar.color = iColor;
                 oTempCar.doors = iDoors;
                 oTempCar.mpg = iMpg; //時速
                 oTempCar.showColor = showColor;
                 return oTempCar;
    }

    var car1 = new createCar('red', 4, 23);
    var car2 = new createCar('blue', 3, 25);
    car1.showColor(); //outputs 'red'
    car2.showColor(); //outputs 'blue'
        儘管上述方法從功能上解決了多次創建函數的問題,但該函數看起來不像是對象的方法。所有這些問題引發了開發者定義的構造函數的出現。

2、構造函數方式

     創建構造函數第一步選擇類名,即構造函數的名字,這個名字的首字母大寫。以使它與字母通常是小寫的變量名區分開。

         function Car(iColor, iDoors, iMpg){
                  this.color = iColor;
                  this.doors = iDoors;
                  this.mpg = iMpg;
                  this.showColor = function(){
                  alert(this.color);
        };
    }

    var car1 = new createCar('red', 4, 23);
    var car2 = new createCar('blue', 3, 25);

可以看出其與工廠方式存在以下區別:
a.構造函數內部無創建對象,而是使用this關鍵字。
b.使用new運算符調用構造函數是,在執行第一行代碼前先創建一個對象,只有用this才能訪問該對象。然後可以直接賦予this屬性,默認情況下是構造函數的返回值。但是構造函數方式與工廠方式一樣,會重複生成函數,爲每個對象都創建獨立的函數版本。

3、原型方式

        該方式利用了對象的prototype對象,可把它看成創建新對象所依賴的原型。
        這裏用空構造函數來設置類名,然後所有的屬性和方法都沒直接賦予prototype屬性。重寫前面的例子代碼如下:

    function Car(){}
         Car.prototype.color = 'red';
         Car.prototype.doors = 4;
         Car.prototype.mpg = 23;
         Car.prototype.showColor = function(){
        alert(this.color);
    };

    var car1 = new Car();
    var car2 = new Car();

         在這段代碼中,首先定義構造函數Car(),接下來的幾行代碼,通過給Car的prototype屬性添加屬性去定義Car對象的屬性。調用new Car()是,原型的所有屬性都被立即賦予要創建的對象,意味着所有Car實例存放的都是指向showColor()函數的指針。從語義上將,所有屬性看起來都屬於一個對象,以此解決了前面兩種方式存在的問題。此外,使用該方法,還能instanceof運算符檢查給定變量指向的對象的類型。因此,下面的代碼將輸出true:alert(car1 instanceof Car); //outputs 'true'看起來是個非常好的解決方案。遺憾的是,它並不盡如人意。首先,這個構造函數沒有參數。使用原型方式時不能通過構造函數傳遞參數初始化對象屬性。真正的問題並不在這裏,而是出現在屬性指向的是對象,而不是函數時。函數共享是不會出現問題的,但對象卻很少是被多個實例共享的。

例如:

    function Car(){}
         Car.prototype.color = 'red';
         Car.prototype.doors = 4;
         Car.prototype.mpg = 23;
         Car.prototype.drivers = new Array('Mike', 'Sue');
         Car.prototype.showColor = function(){
         alert(this.color);
    };

    var car1 = new Car();
    var car2 = new Car();   
    car1.drivers.push('Mart');
    alert(car1.drivers); //outputs 'Mike, Sue,Mart'
    alert(car2.drivers); //outputs 'Mike, Sue,Mart'

         這裏,屬性drivers是指向Array對象的指針,該數組中包含兩個名字'Mike'和'Sue'。由於drivers是引用值,Car的兩個實例都指向同一個數組。這意味着car1.drivers添加值'Matt',在car2.drivers中也能看到。輸出這兩個指針中的任何一個,結果都是現實字符串'Mike, Sue,Mart'。那麼該如何解決以上提出的問題呢?

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

        用構造函數定義對象的所有非函數屬性,用原型方式定義對象的函數屬性(方法),所有函數都只創建一次,而每個對象都具有自己的對象屬性實例。

                   function Car(iColor, iDoors, iMpg){
                           this.color = iColor;
                           this.doors = iDoors;
                           this.mpg = iMpg;
                           this.drivers = new Array('Mike', 'Sue');
                   }

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

        var car1 = new createCar('red', 4, 23);
        var car2 = new createCar('blue', 3, 25);   
        car1.drivers.push('Mart');   
        alert(car1.drivers); //outputs 'Mike, Sue,Mart'
        alert(car2.drivers); //outputs 'Mike, Sue'

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

5、動態原型方式

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

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

         簡而言之,該方法使用標誌(_initialized)來判斷是否已給原型賦予了任何方法。該方法只創建並賦值一次,更符合其他語言中類的定義了。

6、混合工廠方式

         它的目的是創建假構造函數,只返回另一種對象的新實例。

         function Car(){
                     var oTempCar=new Object;
                     oTempCar.color=”red”;
                     oTempCar.doors=4;
                     oTempCar.mpg=23;
                     oTempCar.showColor=function(){
         alert(this.color);
};
return oTempCar;
}

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

原創文章,轉載請註明: 轉載自http://www.yiiyaa.net/
本文鏈接地址: http://www.yiiyaa.net/711
發佈了6 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章