Javascript 中的建構子與其他語言相比也是不同的。任何透過關鍵字 new 呼叫的函數都可以當做建構函數。
在建構函式體內,this 指向新建立的物件。如果建構函式體內沒有顯示的 return 表達式,那麼我們就預設回傳 this,也就是新建的物件。
上面的程式碼將 Foo 當作建構函式進行調用,並將新物件的原型(__proto__)指向了 Foo.prototype。
如果我們在建構函式內定義傳回的 return 表達式,建構函式就會傳回整個表達式,但這個回傳表達式必須為一個物件。
如果 new 被省略,那麼函數將無法傳回一個新的物件。
上面的範例可能在某些場景下也可以運行,但由於 Javascript 中 this 的工作機制,這裡 this 將指向全域物件。
工廠模式
為了能夠不使用關鍵字 new,建構函式將不得不顯示傳回一個值。
上例中使不使用 new 來呼叫函數 Bar 達到的效果是一樣的,將會傳回一個新建的包含 method 方法的對象,這裡其實就是一個閉包。
這裡要注意一點,new Bar() 將不會傳回 Bar.prototype,而是在 return 表達式內函數 method 的原型物件。
上例中,使用 new 與否在功能上是無差異的。
透過工廠模式建立新的物件
我們經常被提醒不要使用 new,因為一旦忘記了它的使用將導致錯誤。
為了創建一個對象,我們更願意使用工廠模式並在工廠模式內建構一個新的對象。
var private = 2;
obj.someMethod = function(value) {
this.value = value;
}
obj.getPrivate = function() {
return private;
}
return obj;
}
儘管上例程式碼比使用 new 時更不容易出錯,而且在使用私有變數時將更加方便,但同時也有一些不好的地方:
因為不能共享原型對象,所以需要更多的記憶體。
為了實現繼承,工廠模式需要拷貝另一個物件的所有方法或將其作為新物件的原型。
放棄原型鏈只是為了避免使用 new,這似乎與 Javascript 語言的精神相反。
總結
儘管使用 new 可能比較容易產生錯誤,但這並不能成為放棄使用原型鏈的原因。至於最後採取哪種方式,這需要根據應用的需求而定。最好的方式就是選擇一種風格並堅持下去。
簡單的說構造函數就是初始化一個實例對象,而對象的prototype屬性是繼承一個實例對象。