1.最簡單的方法,建立一個物件,然後新增屬性
1 var person = new Object(); 2 person.age = 23; 3 person.name = "David"; 4 person.job = "student"; 5 person.sayName = function () 6 { 7 alert(this.name); 8 }; 9 10 //類似於定義鍵值對或者json資料格式的定義方法. 11 var person = 12 { 13 age:23, 14 name:"David", 15 job:"student", 16 sayName:function() 17 { 18 alert(this.name); 19 } 20 };
該方法簡單明瞭,缺點就是當要建立多個同型別的物件時,重複性的程式碼較多.
2.解決方法1中的問題,借鑑許多軟體設計的思想,引入工廠模式,即構造一個建立物件的工廠函式,實現物件建立的功能.
1 function createPerson(name,age,job) 2 { 3 var o = new Object(); 4 o.name = name; 5 o.age = age; 6 o.job = job; 7 o.sayName = function() 8 { 9 alert(this.name); 10 }; 11 return o; 12 } 13 var person = createPerson("David",23,"student");
該方法解決了程式碼重複的問題,可以利工廠函式建立出多個物件.但此方法返回的物件都是Object型別,不能標識建立的物件的型別屬性.
3.建構函式模式,建立建構函式,結合new操作符可以建立物件
1 function Person(name,age,job) 2 { 3 this.name = name; 4 this.age = age; 5 this.job = job; 6 this.sayName = function() 7 { 8 alert(this.name); 9 } 10 } 11 var person1 = new Person("David",23,"student"); 12 var person2 = Person("Bill",21,"Boss"); 13 person1.sayName(); //顯示David 14 person2.sayName(); //顯示undefined 15 sayName(); //顯示Bill
person1 結合new 操作建立了一個物件例項,但person2沒有結合new,直接呼叫Person(name,age,job)函式,此時,函式的作用域裡的this指的是window,因而出現後兩行的顯不結果.安全的建構函式可以避免出現上述的問題
1 function Person(name,age,job) 2 { 3 if(this instanceof Person) 4 { 5 this.name = name; 6 this.age = age; 7 this.job = job; 8 this.sayName = function() 9 { 10 alert(this.name); 11 } 12 } 13 else 14 return new Person(name,age,job); 15 }
this instanceof Person 檢測當前this是否指向到Person物件. 這樣改進後,將不會出上面描述的問題.關鍵是理解this是指向當前執行環境的,關於函式的執行環境以及作用域鏈,以後再作介紹.一般型別的方法是一樣的,可以共享,但使用該方法,每建立一個物件,都會建立一個方法的副本,產生程式碼的重複性.
4.解決該問題,可以把方法置於建構函式體外定義,建構函式內只需要引用在建構函式外定義的函式即可.
1 function Person(name,age,job) 2 { 3 this.name = name; 4 this.age = age; 5 this.job = job; 6 this.sayName = sayName; 7 } 8 9 function sayName() 10 { 11 alert(this.name); 12 }
這樣可以解決方法共享的問題,但會引入其他問題,這樣將導致global scope裡將會有許有方法,使用global scope過於龐大,這樣不便於程式碼管理,方法和相應的屬性分開.
5.原型模式.
1 function Person(){} 2 Person.prototype.name = "David"; 3 Person.prototype.age = 23; 4 Person.prototype.job = "student"; 5 Person.prototype.sayName = function() 6 { 7 alert(this.name); 8 }; 9 var person1 = new Person(); 10 var person2 = new Person();
通過設定建構函式的原型,來達到物件中屬性和方法的共享,person1和person2中對應的屬性和方法都是一樣的. 雖然這種方法,實現了程式碼共享,減少了程式碼的重複,但並不符合人們的需求,一般都是需要各個物件既有共享的方法和屬性,又有各自的特點和屬性.而且這種方法不能傳遞初始化引數,預設構造的物件都具有與原型相同的屬性.
6.原型和建構函式混合模式 利用原型來設定方法,達到方法的共享,利用建構函式來實現屬性的設定,支援初始化引數傳遞,達到屬性的個性化
1 function Person(name,age,job) 2 { 3 this.name = name; 4 this.age = age; 5 this.job = job; 6 } 7 Person.prototype = { 8 constructor:Person, 9 sayName:function() 10 { 11 alert(this.name); 12 } 13 }; 14 var person1 = new Person("David",23,"student"); 15 var person2 = new Person("Bill",21,"Boss");
這樣person1和person2對應的屬性不共享,但方法sayName共享.該方法基本可以滿足一般使用者建立物件的需求.該方法存在一點不好,就是方法和屬性要分開設定,而且在利用原型設定方法時,若是重寫原型,則必須指定constructor為建構函式,若是隻設定相應的屬性,如Person.prototype.sayName = function(){};則不需要指定constructor屬性.
7.動態原型模式 可以將屬性和方法設定一起置於建構函式內.
1 function Person(name,age,job) 2 { 3 this.name = name; 4 this.age = age; 5 this.job = job; 6 7 if(typeof this.sayName != "function") 8 { 9 Person.prototype.sayName = function() 10 { 11 alert(this.name); 12 }; 13 } 14 }
檢測this.sayName是否已經定義,若定義了,則不用設定原型.否則,設定原型定義sayName函式.這種方法同樣可以達到屬性個性化,方法共享的要求
總結,以上就是幾種關於物件建立的方法的總結,逐步完善,從每種方法存在的問題出發,從而尋找更好的解決方法,這樣可以進一步的理解javascript中各種機制設計的最初目的.