js中創(chuàng)建對(duì)象的幾種方式

博客原文地址:Claiyre的個(gè)人博客 https://claiyre.github.io/
博客園地址:http://www.cnblogs.com/nuannuan7362/
如需轉(zhuǎn)載荧呐,請(qǐng)?jiān)谖恼麻_(kāi)頭注明原文地址
士不可以不弘毅愁拭,任重而道遠(yuǎn)册养。

前言

不管是哪門語(yǔ)言蕊梧,千變?nèi)f化不離其宗,深入理解其本質(zhì)梁棠,方能應(yīng)用自如置森。對(duì)應(yīng)到j(luò)s,閉包符糊,原型凫海,函數(shù),對(duì)象等是需要花費(fèi)大功夫思考濒蒋、理解的盐碱。本文穿插了js原型和函數(shù)的相關(guān)知識(shí)把兔,討論了批量創(chuàng)建對(duì)象的幾種方式以及它們的優(yōu)缺點(diǎn)沪伙。

正文

說(shuō)起創(chuàng)建對(duì)象,最容易想到的便是通過(guò)對(duì)象字面量方式直接定義一個(gè)對(duì)象吧县好,但這種方式只能創(chuàng)建少量围橡,單獨(dú)且相互間無(wú)聯(lián)系的對(duì)象。若要批量創(chuàng)建對(duì)象缕贡,該如何翁授?

工廠模式

工廠模式非常直觀,將創(chuàng)建對(duì)象的過(guò)程抽象為一個(gè)函數(shù)晾咪,用函數(shù)封裝以特定接口創(chuàng)建對(duì)象的細(xì)節(jié)收擦。如下所示:

function createStudent(name,sex,grade){                                                         
    var o = new Object();
    o.name = name;
    o.sex = sex;
    o.grade = grade;

    o.sayName = function(){
        console.log(this.name);
    }
    return o;
}
var s1 = createStudent('Claiyre','famale',1);

通俗地講,工廠模式就是將創(chuàng)建對(duì)象的語(yǔ)句放在一個(gè)函數(shù)里谍倦,通過(guò)傳入?yún)?shù)來(lái)創(chuàng)建特定對(duì)象塞赂,最后返回創(chuàng)建的對(duì)象。
工廠模式雖然可以創(chuàng)建多個(gè)相似的對(duì)象昼蛀,但卻不能解決對(duì)象標(biāo)識(shí)的問(wèn)題宴猾,即怎樣知道一個(gè)對(duì)象的類型圆存。構(gòu)造函數(shù)模式應(yīng)運(yùn)而生。

構(gòu)造函數(shù)模式

構(gòu)造函數(shù)模式是java語(yǔ)言創(chuàng)建對(duì)象的通用方式仇哆。兩種語(yǔ)言用構(gòu)造函數(shù)創(chuàng)建對(duì)象的方式略有不同沦辙,注意區(qū)別。
在JavaScript中沒(méi)有類的概念讹剔,函數(shù)即為一等公民油讯,因此,不必顯式聲明某個(gè)類延欠,直接創(chuàng)建構(gòu)造函數(shù)即可撞羽,類的方法和屬性在構(gòu)造函數(shù)中(或原型對(duì)象上)處理。構(gòu)造函數(shù)模式的示例代碼如下:

function Student(name,sex,grade){                                                   
    this.name = name;
    this.sex = sex;
    this.grade = grade;
    this.sayName = function(){
        console.log(this.name);
    }
}
var s2 = new Student('孫悟空'衫冻,'male',2);

細(xì)心的朋友一定發(fā)現(xiàn)了構(gòu)造函數(shù)的函數(shù)名首字母是大寫(xiě)的诀紊,而普通函數(shù)首字母則是小寫(xiě),這是眾多OO語(yǔ)言約定俗成的規(guī)定隅俘,雖然大多數(shù)情況下不大寫(xiě)也不會(huì)報(bào)錯(cuò)邻奠,但是為了代碼的規(guī)范性和可讀性,還是應(yīng)該將構(gòu)造函數(shù)的首字母大寫(xiě)为居,與普通函數(shù)區(qū)別開(kāi)碌宴。
與工廠模式相比,用構(gòu)造模式創(chuàng)建對(duì)象有以下幾點(diǎn)不同:

  • 沒(méi)有顯示地創(chuàng)建對(duì)象
  • 直接將屬性和方法賦給this對(duì)象
  • 沒(méi)有return語(yǔ)句

此外蒙畴,還應(yīng)注意到要?jiǎng)?chuàng)建Student的實(shí)例贰镣,必須要使用new操作符,創(chuàng)建的實(shí)例對(duì)象將有一個(gè)constructor(構(gòu)造器)屬性膳凝,指向Person構(gòu)造函數(shù)碑隆。調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象經(jīng)過(guò)了以下幾個(gè)過(guò)程:

  • 創(chuàng)建一個(gè)新對(duì)象
  • 將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this就指向了這個(gè)新對(duì)象)
  • 執(zhí)行構(gòu)造函數(shù)中的代碼
  • 返回新對(duì)象(不需要顯式返回)

構(gòu)造函數(shù)雖好用,但也不是沒(méi)有缺點(diǎn)蹬音。使用構(gòu)造函數(shù)的主要問(wèn)題是:每個(gè)方法都要在每個(gè)實(shí)例上創(chuàng)建一遍上煤。在ECMAScript中,函數(shù)即對(duì)象著淆,因此每定義一個(gè)函數(shù)劫狠,也就是實(shí)例化了一個(gè)對(duì)象。下面的例子證明了這個(gè)缺點(diǎn)永部。

var s3 = new Student('唐僧','male',3);
var s4 = new Student('白骨精','female',4);
s3.sayName();
s4.sayName();
console.log(s3.sayName == s4.sayName);

運(yùn)行結(jié)果:


也就是說(shuō)通過(guò)構(gòu)造函數(shù)實(shí)例化的多個(gè)對(duì)象的方法独泞,是多個(gè)不同的方法,但它們內(nèi)部的代碼以及實(shí)現(xiàn)的功能是相同的苔埋,這就造成了一定的資源浪費(fèi)懦砂。
幸運(yùn)的是,這個(gè)問(wèn)題可以用原型模式來(lái)解決。

原型模式

js中孕惜,每個(gè)函數(shù)都有一個(gè)prototype屬性愧薛,它是一個(gè)指針,指向一個(gè)對(duì)象衫画,叫做原型對(duì)象毫炉,原型對(duì)象包含了可以由特定類型的所有實(shí)例對(duì)象共享的屬性和方法。此外削罩,這個(gè)對(duì)象有一個(gè)與生自來(lái)的屬性constructor瞄勾,指向創(chuàng)建對(duì)象的構(gòu)造方法。
使用原型模式可以讓所有的實(shí)例共享原型對(duì)象中的屬性和方法弥激,也就是說(shuō)进陡,不必再構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息。用代碼表示如下:

function Student_1(){

}
Student_1.prototype.name = 'Claiyre';
Student_1.prototype.sex = 'female';
Student_1.prototype.class = 5;
Student_1.prototype.sayName = function (){
    console.log(this.name);
}

var s5 = new Student_1();                              
s5.sayName();    //Claiyre
var s6 = new Student_1();
s6.sayName();    //Claiyre

一張圖勝過(guò)千言萬(wàn)語(yǔ)微服,下圖清楚地闡釋了各個(gè)對(duì)象和原型對(duì)象間的關(guān)系:


了解過(guò)原型后趾疚,可以繼續(xù)在實(shí)例對(duì)象上增添屬性或方法:

s6.name = 'John';                             
s6.sayName();       //John

當(dāng)要讀取某個(gè)對(duì)象的屬性時(shí),都會(huì)執(zhí)行一次搜索以蕴,搜索首先從對(duì)象實(shí)例本身開(kāi)始糙麦,如果在實(shí)例中找到了這個(gè)屬性,則搜索結(jié)束丛肮,返回實(shí)例屬性的值赡磅;若實(shí)例上沒(méi)有找到,則繼續(xù)向?qū)ο蟮脑蛯?duì)象延伸宝与,搜索對(duì)象的原型對(duì)象焚廊,若在原型對(duì)象上找到了,則返回原型上相應(yīng)屬性的值习劫,若沒(méi)有找到咆瘟,則返回undefined。因此榜聂,實(shí)例對(duì)象屬性會(huì)覆蓋原型對(duì)象上的同名屬性搞疗,所以上面第二行代碼輸出的是John嗓蘑。

  • Object.getPrototypeOf(object)方法返回參數(shù)對(duì)象的原型對(duì)象须肆。
  • Object.keys(object)方法返回對(duì)象上課枚舉的實(shí)例屬性。

原型中的所有屬性都是被所有實(shí)例所共享的桩皿,這種共享對(duì)于函數(shù)來(lái)說(shuō)非常合適豌汇,對(duì)于包含基本值的屬性也說(shuō)的過(guò)去(實(shí)例屬性會(huì)覆蓋原型同名屬性),但對(duì)于那些包含引用類型的屬性泄隔,可有大麻煩了

Student_1.prototype.friends = ['aa','bb'];

console.log('s6的朋友' + s6.friends);
s5.friends.push('cc');
console.log('s5的朋友' + s5.friends);
console.log('s6的朋友' + s6.friends);

運(yùn)行結(jié)果:


問(wèn)題來(lái)了拒贱,我們只想改變s5的朋友列表,但由于原型模式的共享本質(zhì),s6的朋友列表也隨之改變了逻澳。
因此闸天,很少單獨(dú)使用原型模式。

組合使用構(gòu)造函數(shù)和原型模式

構(gòu)造函數(shù)模式用于定義實(shí)例屬性斜做,原型模式則用于定義方法和共享的屬性苞氮。這種混合模式不僅支持向構(gòu)造函數(shù)傳入?yún)?shù),還最大限度地節(jié)約了內(nèi)存瓤逼,可謂是集兩模式之長(zhǎng)笼吟。示例代碼如下:

function Student(name,sex,grade){                   
    this.name = name;
    this.sex = sex;
    this.grade = grade;
}

Student.prototype.sayName = function(){
        console.log(this.name);
}
Student.prototype.school = 'Joooh school';

其他模式

除了以上幾種常見(jiàn)的模式外,批量創(chuàng)建對(duì)象的方式還有

  • 動(dòng)態(tài)原型模式:僅在第一次調(diào)用構(gòu)造函數(shù)時(shí)霸旗,將方法賦給原型對(duì)象的相應(yīng)屬性贷帮,其他示例的處理方式同構(gòu)造函數(shù)模式
  • 寄生構(gòu)造函數(shù)模式:僅僅封裝創(chuàng)建對(duì)象的代碼,然后再返回新創(chuàng)建的對(duì)象诱告,仍使用new操作符調(diào)用
  • 穩(wěn)妥構(gòu)造函數(shù)模式:沒(méi)有公共屬性撵枢,只有私有變量和方法,以及一些get/set方法精居,用以處理私有變量诲侮。

結(jié)語(yǔ)

每種模式都有各自的優(yōu)缺點(diǎn),具體要使用哪種箱蟆,還需結(jié)合實(shí)際場(chǎng)景沟绪,深入理解,靈活運(yùn)用空猜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绽慈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子辈毯,更是在濱河造成了極大的恐慌坝疼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谆沃,死亡現(xiàn)場(chǎng)離奇詭異钝凶,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)唁影,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門耕陷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人据沈,你說(shuō)我怎么就攤上這事哟沫。” “怎么了锌介?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵嗜诀,是天一觀的道長(zhǎng)猾警。 經(jīng)常有香客問(wèn)我,道長(zhǎng)隆敢,這世上最難降的妖魔是什么发皿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮拂蝎,結(jié)果婚禮上雳窟,老公的妹妹穿的比我還像新娘。我一直安慰自己匣屡,他們只是感情好封救,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著捣作,像睡著了一般誉结。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上券躁,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天惩坑,我揣著相機(jī)與錄音,去河邊找鬼也拜。 笑死以舒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慢哈。 我是一名探鬼主播蔓钟,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼卵贱!你這毒婦竟也來(lái)了滥沫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤键俱,失蹤者是張志新(化名)和其女友劉穎兰绣,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體编振,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缀辩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了踪央。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臀玄。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖杯瞻,靈堂內(nèi)的尸體忽然破棺而出镐牺,到底是詐尸還是另有隱情,我是刑警寧澤魁莉,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響旗唁,放射性物質(zhì)發(fā)生泄漏畦浓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一检疫、第九天 我趴在偏房一處隱蔽的房頂上張望讶请。 院中可真熱鬧,春花似錦屎媳、人聲如沸夺溢。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)风响。三九已至,卻和暖如春丹禀,著一層夾襖步出監(jiān)牢的瞬間状勤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工双泪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留持搜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓焙矛,卻偏偏與公主長(zhǎng)得像葫盼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子村斟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容