Javascript創建自定義對象

雖然Object構造函數或對象字面量都可以用老創建單個對象,但這些方式都有個明顯的缺點:實用同一個接口創建很多對象,會產生大量重複代碼。爲解決這個問題,人們開始使用類似共產模式的方式

1.工廠模式

function createPerson(name,age,job){

var o=new Object();

o.name=name;

o.age=age;

o.job=job;

o.SayName=function(){

alert(this.name);

};

return o;

}

var person1=createPerson("tom",9,"student");

var person2=createPerson("Greg",27,"Doctor");

函數createPerson()能夠根據接收的參數來創建一個包含所有必要信息的Person對象。可以無數次的調用這個函數,而每次調用它都會返回一個包含三個屬性一個方法的對象。工廠模式雖然解決了創建多個相似對象的問題,卻沒有解決怎樣知道一個對象的類型。隨着javascript的發展,又一個模式出現了。

2.構造函數模式

function Person(name,age,job){

this.name=name;

this.age=age;

this.job=job;

this.sayName=function(){

alert(this.name);

};

}

var person1=new Person("tom",9,"student");

var person2=new Person("Greg",27,"Doctor");

要創建Person的新實例,必須使用new操作符。以這種方式調用構造函數會經歷以下四個步驟:

(1)、創建一個對象;

(2)、將構造函數的作用域賦給新對象(因此this指向了這個新對象);

(3)、執行構造函數中的代碼(爲這個新對象添加屬性);

(4)、返回新對象。

創建自定義的構造函數意味着可以將它的實例標識爲一種特定的類型;而這正是構造函數模式勝過工廠模式的地方。

2.1將構造函數當做函數

構造函數與其他函數的唯一區別就是調用他們的方式不同。不過,構造函數畢竟是函數,不存在定義構造函數的特殊語法。任何函數,只要通過new操作符來調用,那她就可以作爲構造函數;而任何函數,如果不通過new操作符來調用,那他跟普通函數不會有什麼兩樣。例如。

//當做構造函數來來調用

var person=new Person("Greg",27,"Doctor");

person.sayName();//Greg

//作爲普通函數調用

Person("Greg",27,"Doctor");//添加到window

windo.sayName();//Greg

//在另一個對象的作用域中調用

var o=new Object();

Person.call(o,"Greg",9,"Doctor");

o.sayName();//Greg

2.2構造函數的問題

如上,創建的兩個對象,他們的同名函數是不相等的,然而,創建兩個完成同樣任務的Function實例的確沒有必要;況且有this對象在,根本不用在執行代碼前就把函數綁定到特定對象上。因此,可以像下面這樣,通過把函數定義轉移到構造函數外部來解決這個問題(這是終於明白爲什麼有人說指針是c語言的精髓了)

function Person(name,age,job){

this.name=name;

this.age=age;

this.job=job;

this.sayName=sayName;

}

function sayName(){

alert(this.name);

}

這樣確實解決了兩個函數做同一件事的問題,可是問題又來了:在全局作用域中定義的函數實際上只能被某個對象調用,這然全局作用域有點名不副實。更讓人無法接受的是:如果對象需要需要定義很多方法,那麼就要定義很多個全局函數,於是我們這個自定義的引用類型就絲毫沒有封裝性可言了。好在這些問題可以使用原型模式來解決。

3.原型模式

function Person(){}

Person.prototype.name='tom';

Person.prototype.age=29;

Person.prototype.job="Software Engineer";

Person.prototype.sayName=function(){

alert(this.name);

};

var person1=new Person();

person1.sayName();//tom

var person2=new Person();

person2.sayName();//tom

在使用原型模式時需注意,如果我們給新創建的對象添加的屬性在原型中也有,那麼以後定義這個爲準。

原型模式也不是沒有問題。首先,它省略了爲構造函數傳遞初始化參數這一環節,結果所有實例在默認情況下都將取得相同的屬性值。雖然這會在某種程度上帶來一些不方便,但還不是原型模式的最大問題。

原型模式的最大問題是由其共享的本性所導致的。

原型中的所有屬性是被很多實例共享的,這種共享對於函數非常合適。對於那些包含基本值的屬性倒也說得過去,畢竟,通過在實例上添加一個同名屬性可以隱藏原型中的對應屬性,然而,對於包含引用類型值得屬性來說,問題比較突出了

function Person(){}

Person.prototype={

conctructor:Person,

name:"tom",

age:29,

job:"Software Engineer",

friends:["eric","jassy"],

sayName:function(){

alert(this.name);

}

};

var person1=new Person();

var person2=new Person();


person1.friends.push("Van");


alert(person1.friends);//eric,jassy,Van

alert(person2.friends);//eric,jassy,Van

看到了吧。。。


4.組合使用構造函數模式和原型模式

構造函數模式用於定義實例屬性,而原型模式則用於定義方法和共享的屬性。

function Person(name,age,job){

this.name=name;

this.age=age;

this.job=job;

this.friends=['eric',"jassy"];

}

Person.prototype={

constructor:Person,

sayName:function(){

alert(this.name);

}

}


5.動態原型模式

function Person(name,age,job){

//屬性

this.name=name;

this.age=age;

this.job=job;

//方法

if(typeof this.sayName!="function"){

Person.prototype.sayName=function(){

alert(this.name);

};

}

}

var friend=new Person("Eric",29,"Software Engineer");

friend.sayName();

使用動態原型模式時,不能使用對象字面量重寫原型,如果在已經創建了實例的情況下重寫原型,那麼就會切斷現有實例與新原型之間的聯繫


6.寄生構造函數模式

通常,在前述幾種模式都不適用的情況下,可以使用寄生構造函數模式。這種模式的基本思想是創建一個函數,該函數的作用僅僅是封裝創建對象的代碼,然後再返回新創建的對象;但從表面上看,這個函數又像是很典型的構造函數

function Person(name,age,job){

var o=new Object();

o.name=name;

o.age=age;

o.job=job;

o.sayName=function(){

alert(this.name);

};

return o;

}

var friend=new Person("Eric",29,"SoftWare Engineer");

friend.sayName();//Eric

在這個例子中,Person創建了一個新對象,並以相應的屬性和方法初始化該對象,然後又返回了這個對象。除了使用new操作符並把使用的包裝函數叫做構造函數之外,這個模式跟工廠模式其實是一模一樣的。構造函數在不返回值得情況下,默認會返回新對象實例,而通過在構造函數的末尾添加一個return語句,可以重寫調用構造函數時返回的值。

這個模式可以再特殊的情況下用來爲對象創建構造函數。假設我們想創建一盒具有額外方法的特殊數組,由於不能直接修改Array構造函數,因此可以使用這個模式。

function SpecialArray(){

//創建數組

var values=new Array();

//添加值

values.push.apply(values,arguments);

//添加方法

values.toPipedString=function(){

return this.join("|");

};


//返回數組

return values;

}

var colors=new SpecialArray("red","blue","green");

alert(colors.toPipedString())//red|blue|green

首先,返回的對象與構造函數或者構造函數的原型屬性之間沒有關係;也就是說,構造函數返回的對象與在構造函數外部創建的對象沒有什麼區別,爲此,不能依賴instanceof操作符來確定對象類型


7,穩妥構造函數模式

所謂穩妥對象,指的是沒有公共屬性,而且其他方法也不引用this的對象。

function Person(name,age,job){

//創建要返回的對象

var o=new Object();

//可以再這裏定義私有變量和函數


//

添加方法

o.sayName=function(){

alert(name);


//返回對象

return o;

};

注意,這種模式創建的對象中,除了使用sayName方法外,沒有其他方法訪問name的值。可以像下面使用穩妥的Person構造函數

var friend=Person("Eric",29,"Software Engineer");

friend.sayName();

這樣,變量friend中保存的是一個穩妥對象,而除了sayName()方法外,沒有別的方式可以訪問傳入到構造函數中的原始數據。穩妥構造函數模式提供這種感覺安全性,使得他非常適合在某些安全執行環境下使用。

}


發佈了31 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章