2016年2月14日 星期日

JavaScript 建立物件的幾種方法與優缺點分析

    JavaScript 是一種物件導向的程式語言,但確不存在類別的概念,這跟我們以往在 JavaC++C# 等語言上所學到的物件導向觀念有很大的不同,也是一般JavaScript 初學者所要適應與轉變的觀念。談 OOP 總離不開封裝、繼承與多型等基本觀念,而 JavaScript 在實作這三者時與JavaC++C# 等語言也有著截然不同的作法,唯有先搞清楚 JavaScript 中原型式的物件導向觀念與作法,才能在使用 JavaScript 這門語言時游刃有餘。首先我們將透過如何在 JavaScript 中建立物件的幾種方式來展開 JavaScript  OOP 之旅

   JavaScript 中要建立一個物件,非常簡單,不像JavaC++C# 等語言要透過  Class 才有辦法建立一個物件
第一種方法是透過所謂的實字符號模式(literal notation patterns) ,快速的建立一個物件,如下程式片段:

var dog = {};     //空物件
dog.name = “harry”;
dog.getName = function(){
     return dog.name;
};
也可以這樣建立一個新物件:
var dog = {
     name: “harry”,
     getName: function(){
          return this.name;   //or return name
}
};

當我們只想為物件建立一個執行個體時,會使用此方式,此方式不適合於需建立多個相同物件模板的運用
第二種方式是透過內建的建構式(constructor functions)來建立一個新的物件:

var dog = new Object();//空物件,但會自動從 Object.prototype 承屬性與方法
console.log(dog.constructor === Object)’ //true
dog.name = “harry”;

此種方式也只適用於想為物件建立一個執行個體時使用
另外需注意的是: Object 可以接受一個參數此時傳回的就不一定是 Object 如下例:

var obj = new Object(1);
console.log(o.constructor === Number); //true
var obj = new Object(“harry”);
console.log(o.constructor === String); //true
var obj = new Object(true”);
console.log(o.constructor === Boolean); //true

 所以在使用上時要別別小心,尤其是在動態建立物件的情況下,可能很容易得到不如預期的結果。
第三種方法是透過自訂建構式函式來建立新物件,透過這種方式建立物件,JavScript 引擎會在背後做一些事,如下例:

var Dog = function(name){
     //使用物件實字自動建立一個空物件
     // var this = Object.create(Dog.prototype);
     this.name = name;
     this.getName = function(){
          return this.name;
};
// return this;  //隱式傳回 this 物件
};

var dog = new Dog(“harry”);  //雖然很像 Java c# 中透過類別建立物件的方式,但它並不是,它稱為函式建構子
dog.getName; //harry

這種建立物件的方式有一個缺點,就是你每建立一個新的物件,就會有一個新的屬性及方法被建立在記憶體中,對於物件的屬性來說是合理,因為每個物件的屬性值本來就會有所不同,但對於可重覆利用的方法來說,很明顯這是一種記憶體上的浪費,應該透過如下的程式片段來達成方法的共用:

var Dog = function(name){
     this.name = name;    
};
Dog.prototype.getName = function(){
     return this.name;
};

這樣當透過自訂建構式函式建立二個以上的物件時,實際上只會在記憶體建立一份方法:

var dog1 = new Dog(“harry”);
dog1.getName; //harray
var dog2 = new Dog(“marry”);
dog2.getName; // marry

自訂建構式函式時,也可以透如下的方式定義屬性和方法
var Dog = function({   
};
Dog.name = “harray”;
Dog.getName = function(){
     return this.name;
};

但需注意的是透過這種方式宣告的屬性與方法稱為靜態屬性與方法,有如下的特性:

console.log(Dog.name); //harry
console.log(typeof Dog. getName); //function
           
var o=new Dog ();
console.log(o.name); //undefined
console.log(typeof o. getName); //undefined

另外關於自訂建構式函式需要注意的是一定要使用 new 來建立物件,如果忘了使用 new  在建構式中的 this 就會指向全域物件,也就是在瀏覽器中, this 就指向 window

var dog = Dog();
console.log(typeof dog); // undefined 忘了new, 不會有物件this回傳 變成全域
console.log(window.name); //全域變數

可以透過下列的技巧讓自訂建構式函式無論使用那一種方式,一定會回傳物件:


優點
缺點
實字物件建立方法
快速而簡潔的建立單一物件。
無法透過它去完成建立同一類型物件的多個實例。
內建建構式函式
可透過參數建立不同型別的物件
1.      無法透過它去完成建立同一類型物件的多個實例。
2.      當傳入不同參數會得到不同的預期結果。所以通常不建議採用此方法來建立新物件,可直接採用實字法。
自訂建構式函式
1.      可以建立同一類型物件的多個實例。
2.      可以建立靜態屬性與方法,使之成為工具類別,服務整個應用。
建立方式比較複雜,需了解不同建立方式間的區別。


在上面三種建立物件的方法時,有二個  keyword 出現,一個是 prototype constructor,下一篇文章,我們將介紹這二個 keyword 讓我們向 JavaScript 式的 OOP 更接近一步。
參考文件:

沒有留言:

張貼留言