楔子
問題
在 java 中,首先定義一個 class遭顶,然后 new 出該 class 的實例喇聊,那么無論 new 多少次,新出現(xiàn)的類永遠都具有 class 中定義的屬性务豺。
但 js 中不一樣磨总,js 中為某個對象新添加的屬性,不會出現(xiàn)在新對象中笼沥。如下:
var o1 = {}
o1.name = 'o1.name'
var o2 = {}
alert(o2.name)
首先為 o1 創(chuàng)建 name 屬性蚪燕,但這個屬性并沒有被帶到 o2 中,如果 o2 也想具有與 o1 一樣的屬性奔浅,就需要將 o1 的屬性定義全部重寫一遍馆纳。這就導致了一個問題 想要創(chuàng)建一個類似的對象,就需要寫很多重復代碼汹桦。
假設有對象 A鲁驶,現(xiàn)在想創(chuàng)建一個跟 A 只有一個屬性不同的對象 B。按上述思路舞骆,我們需要重新創(chuàng)建一個 B 對象钥弯,然后將 A 径荔、B 對象共用的屬性與方法賦值給 B,代碼繁瑣寿羞。
工廠方法模式
為解決上述問題猖凛,可以使用工廠方法模式。
function createObj(){
var d = new Object();
d.h='h';
return d;
}
通過上述方法產生的對象都會具有 h 屬性绪穆。但由于工廠方法具有封裝性辨泳,外界使用者根本不知道產生的對象是哪一個類的實例,也無法修改返回對象對應的類玖院,因此菠红,使用者可能沒辦法調用某些類特有的方法。
例如使用 createObj 方法產生對象后难菌, 想調用 getFullYear() 方法是不可能的试溯。因此 Object 對象沒有 getFullYear() 方法。如果想使用 getFullYear() 就需要改成如下代碼:
function creatObj2(){
var d = new Date();
d.h='h';
return d;
}
這會有幾個問題:1郊酒,使用者不能修改工廠方法里的代碼遇绞;2. 即使修改了,也沒有辦法保證工廠方法能兼容所有的類燎窘,類的個數(shù)無限摹闽,不可能為每一個類創(chuàng)建一個工廠方法。
構造函數(shù)
構造函數(shù)也是函數(shù)褐健,也可以直接調用付鹿;每一個函數(shù)都可以轉成構造函數(shù),從而可以創(chuàng)建實例
-
與 new 關鍵字結合時蚜迅,普通函數(shù)會轉為構造函數(shù)舵匾,進而創(chuàng)建出一個對象,該類的類名就是構造函數(shù)的方法名
var o = function(){ this.age = arguments[0]; // this 指代的是新創(chuàng)建出來的對象 } var oo = new o('age'); // 與 new 關鍵字結合谁不,轉為構造函數(shù)坐梯,進而創(chuàng)建一個實例 alert(oo.age) alert(oo instanceof o) // true o('直接調用'); //直接調用時,this 指代的是 window alert(window.age+",from window") // 所以 window.age 輸出的是 ‘直接調用’
-
由于 this 指代的是當前對象拍谐,所以在構造函數(shù)中的 this 指的就是新創(chuàng)建的對象烛缔。
function Demo(){ this.m = function(){ alert('this is m ') } } var o = new Object(); Demo.call(o) o.m()
如果不調用 Demo.call() 就沒辦法直接調用 o.m() ,因為 Object 類中沒有方法名為 m 的方法轩拨。
調用 call 方法后践瓷,相當于在 o 對象中運行了一次 Demo 方法,而其中的 this 指的就是 o 對象亡蓉,所以 o 對象中已經具有了 m 方法晕翠。 -
與工廠方法相比,構造函數(shù)有如下優(yōu)點:
沒有 new Object()
直接將屬性賦值給 this ,而不是賦值給一個 Object 對象
不需要直接返回一個對象淋肾。
返回的對象不但 instanceof Object 硫麻,而且還 instanceof 構造函數(shù)對應的類。
構造函數(shù)實質上與工廠方法一樣樊卓,只不過 new Object() 與 return 語句是在后臺進行拿愧。構造函數(shù)算是一個改良后的工廠方法。
一般來說碌尔,構造函數(shù)首字母大寫浇辜,而普通函數(shù)不需要。