一、對象創建方式 1. 工廠模式 這種模式抽象了創建具體對象的過程,用函數來封裝以特定介面創建對象的細節。存在的問題是無法通過 instanceof 識別一個對象的類型。 2. 構造函數模式 創建自定義的構造函數,從而定義自定義對象類型的屬性和方法。利用構造函數模式創建實例對象時,必須使用new操作 ...
一、對象創建方式
1. 工廠模式
這種模式抽象了創建具體對象的過程,用函數來封裝以特定介面創建對象的細節。存在的問題是無法通過 instanceof 識別一個對象的類型。
1 function createPerson(name,age,job){ 2 var o=new object(); 3 o.name=name; 4 o.age=age; 5 o.job=job; 6 o.sayName=function(){ 7 alert(this.name); 8 } 9 return o; 10 } 11 12 var person=createPerson("Greg","27","Doctor");
2. 構造函數模式
創建自定義的構造函數,從而定義自定義對象類型的屬性和方法。利用構造函數模式創建實例對象時,必須使用new操作符,並可以通過 instanceof 檢測到對象的自定義類型。
1 function Person(name,age,job){ 2 this.name=name; 3 this.age=age; 4 this.job=job; 5 this.sayName=function(){ 6 alert(this.name); 7 } 8 } 9 10 var person=new Person("Greg","27","Doctor");//1.創建一個新對象;2.將構造函數的作用域賦給新對象(this指向新對象);3.執行構造函數中的代碼;4.返回新對象
此時存在的問題是自定義對象中定義的方法都要在每個實例上重新創建一遍,也就是說不同實例上的同名函數是不相等的。雖然可以通過將函數定義轉移到構造函數外來解決,這時每個實例中的函數引用的都是在全局作用域中定義的一個全局函數。但是這又帶來了新的問題,就是當對象需要定義很多方法時,就需要定義很多個全局函數。
3. 原型模式
我們創建的每個函數都有一個prototype(原型)屬性,它是一個指針,指向一個對象,即原型對象,原型對象可以讓所有對象實例共用它所包含的屬性和方法。存在的問題是所有實例在預設情況下都將取得相同的屬性值。
1 function Person(){ 2 } 3 4 Person.prototype={ 5 constructor:Person,//這裡實際上是重寫了Person的原型對象,因此其constructor指向的是Object構造函數,此時通過instanceof能識別到特定類型,但其constructor已經無法確定對象類型了,因此可以重新將它設置回適當的值。 6 name:"Nicholas", 7 age:29, 8 job:"Doctor", 9 sayName:function(){ 10 alert(this.name); 11 } 12 }; 13 14 var person=new Person();
4. 組合使用構造函數模式和原型模式
這是創建自定義類型的最常見方法,構造函數模式用於定義實例屬性,原型模式用於定義方法和共用的屬性。
1 function Person(name,age,job){ 2 this.name=name; 3 this.age=age; 4 this.job=job; 5 this.friends=["Shelby","Court"]; 6 } 7 8 Person.prototype={ 9 constructor:Person, 10 sayName:function(){ 11 alert(this.name); 12 } 13 } 14 15 var person=new Person("Greg",27,"Doctor");
5. 動態原型模式
把所有信息都封裝在構造函數中,通過在構造函數中初始化原型,保持了同時使用構造函數和原型的優點。也就是說可以通過檢查某個應該存在的方法是否有效,來決定是否需要初始化原型。這時不能用對象字面量重寫原型,如果在以及創建了實例的情況下重寫原型,會切斷現有實例與新原型之間的聯繫。
1 function Person(name,age,job){ 2 this.name=name; 3 this.age=age; 4 this.job=job; 5 6 if(typeof this.sayName != "function"){ 7 Person.prototype.sayName=function(){ 8 alert(this.name); 9 } 10 } 11 } 12 13 var person=new Person("Greg","27","Doctor");
6. 寄生構造函數模式
這種模式除了使用new操作符創建實例對象並把使用的包裝函數稱作構造函數之外,與工廠模式是一樣的。這個模式可以在特殊情況下用來為對象創建構造函數,如想創建一個具有額外方法的特殊數組。但需要註意的是返回的對象與構造函數以及構造函數的原型屬性之間沒有關係,因此不能通過instanceof識別對象類型。建議在可以使用其他模式的情況下不要使用這種模式。
7. 穩妥構造函數模式
穩妥對象指的是沒有公共屬性,而且其方法也不引用this的對象,它適合在一些安全的環境中(這些環境中會禁止使用this和new),或者在防止數據被其他應用程式改動時使用。穩妥構造函數與寄生構造函數有類似的模式,但有兩點不同:一是新創建對象的實例方法不引用this;二是不使用new操作符調用構造函數。
二、閉包
閉包是指有權訪問另一個函數作用域中的變數的函數,創建閉包的常見方式就是在一個函數內部創建另一個函數,應用的兩種情況是:一是函數作為返回值;二是函數作為參數傳遞。
由於在另一個函數內部定義的函數會將外部函數的活動對象添加到它的作用域鏈中,因此即使當外部函數返回後,其執行環境的作用域鏈會被銷毀,但它的活動對象仍然留在記憶體中,因為在其內部定義的函數仍然在引用它。
直到內部函數被銷毀後,外部函數的活動對象才會被銷毀。所以使用閉包會增加記憶體開銷。