【20190220】JavaScript-知識點整理:物件建立方式、原型、閉包

dorrri發表於2019-02-20

一、物件建立方式

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操作符呼叫建構函式。

 

二、閉包

閉包是指有權訪問另一個函式作用域中的變數的函式,建立閉包的常見方式就是在一個函式內部建立另一個函式,應用的兩種情況是:一是函式作為返回值;二是函式作為引數傳遞。

由於在另一個函式內部定義的函式會將外部函式的活動物件新增到它的作用域鏈中,因此即使當外部函式返回後,其執行環境的作用域鏈會被銷燬,但它的活動物件仍然留在記憶體中,因為在其內部定義的函式仍然在引用它。

直到內部函式被銷燬後,外部函式的活動物件才會被銷燬。所以使用閉包會增加記憶體開銷。

相關文章