面試中你有被問(wèn)到-javascript中有幾種創(chuàng)建對(duì)象的方式嗎?
Javascript中,所有事物皆為對(duì)象!布爾型,數(shù)字型,字符串,日期,數(shù)學(xué)和正則表達(dá)式,數(shù)組,函數(shù)統(tǒng)統(tǒng)都是對(duì)象。所以,學(xué)好對(duì)象,走遍天下都不怕了!
對(duì)象是一種特殊的數(shù)據(jù),有屬性和方法。通過(guò)創(chuàng)建對(duì)象,可以代碼共享構(gòu)建出形形色色的實(shí)例,從而節(jié)省我們開(kāi)發(fā)的時(shí)間。那如何創(chuàng)建一個(gè)對(duì)象呢?有以下四種:
對(duì)象字面量(又稱(chēng)為直接量,原始方式)
工廠模式(利用函數(shù)創(chuàng)建對(duì)象)
構(gòu)造函數(shù)模式(利用類(lèi)創(chuàng)建對(duì)象)
原型模式(利用函數(shù)的prototype創(chuàng)建對(duì)象)
通過(guò)原型+構(gòu)造函數(shù)的方式創(chuàng)建對(duì)象
使用 Object.create() 方法
使用 ES6 類(lèi)
但不管是哪種方式,都萬(wàn)變不離其宗。用句大實(shí)話(huà)就是,對(duì)象就是一個(gè)大括號(hào)包裹著一些屬性和一些方法的集合,無(wú)非就是是不是以函數(shù)的形式展示。
01
對(duì)象字面量
通過(guò)對(duì)象字面量創(chuàng)建對(duì)象有三種形式:
第一種:{}
舉例:
第二種:new Object()
舉例:
第三種:直接定義
舉例:
這三種方式大同小異,我一般習(xí)慣用第三種方式,因?yàn)楹?jiǎn)單。
小結(jié):
這三種方式,對(duì)象中的方法都是獨(dú)立的,不能共享。如果創(chuàng)建多個(gè)對(duì)象,代碼冗余現(xiàn)象非常嚴(yán)重。
02
工廠模式
工廠模式是以函數(shù)的形式創(chuàng)建對(duì)象。
舉例:
這種方式其實(shí)就是第一種方式加了一層函數(shù)的外殼,外加了一些參數(shù),使其可以批量創(chuàng)建對(duì)象。無(wú)疑,這種方式可以減少代碼的冗余。但是這不是完美的,還有一個(gè)問(wèn)題:age這個(gè)變量,其實(shí)應(yīng)該是Number類(lèi)型,如果我不看源碼,我是不知道的,在傳參的時(shí)可能會(huì)因隨心所欲而出問(wèn)題。
有沒(méi)有發(fā)現(xiàn),per1.dreams和per2.dreams,是不相等的,意味著什么?意味著這個(gè)方法是不共享的,相同的方法會(huì)開(kāi)辟不同的空間,會(huì)浪費(fèi)空間。
小結(jié):
代碼冗余現(xiàn)象有所緩解;
對(duì)象屬性類(lèi)型未知,需要看源碼;
對(duì)象的方法是獨(dú)立的,不能共享。
TIPS:
“?工廠模式一定不要忘記最后要把對(duì)象return出去!”
03
構(gòu)造函數(shù)模式
構(gòu)造函數(shù)一種特殊的函數(shù),其名稱(chēng)的首字母是大寫(xiě)的,而普通函數(shù)名稱(chēng)的首字母小寫(xiě)。與第2種方式的區(qū)別就是,不用首先創(chuàng)建一個(gè)空對(duì)象,往空對(duì)象中添加屬性和方法,最后再return出去。構(gòu)造函數(shù)里的屬性的前綴全部用this代替。this指向的是創(chuàng)建出來(lái)的實(shí)例。創(chuàng)建對(duì)象用new...。
舉例:???????????
new在執(zhí)行時(shí)會(huì)完成以下四件事:
開(kāi)辟新的空間存儲(chǔ)當(dāng)時(shí)對(duì)象;
構(gòu)造函數(shù)中的this指向當(dāng)前對(duì)象;
執(zhí)行構(gòu)造函數(shù)中的代碼,為當(dāng)前對(duì)象添加屬性和方法;
返回新對(duì)象(所以構(gòu)造函數(shù)中不需要return對(duì)象)
小結(jié):
per1和per2同屬于同一個(gè)constructor;
構(gòu)造函數(shù)里的方法是獨(dú)立于每個(gè)對(duì)象的,所以構(gòu)造函數(shù)里的方法不能共享。
相同的方法開(kāi)辟不同的空間,會(huì)造成資源的浪費(fèi)。
04
原型模式
在講這種模式前需回顧一下原型鏈的知識(shí)。
每個(gè)函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象;
每個(gè)原型都有一個(gè)constructor屬性,指向關(guān)聯(lián)的構(gòu)造函數(shù);
_Proto _是每一個(gè)子對(duì)象(除null外)都會(huì)有的一個(gè)屬性,指向該對(duì)象的原型

從上圖可以看出來(lái),Person.prototype相當(dāng)于一個(gè)全局對(duì)象,只不過(guò)這個(gè)對(duì)象有些特殊,它是與構(gòu)造函數(shù)相關(guān)聯(lián)的。per1以及所有Person的實(shí)例都可以繼承實(shí)例原型的屬性或者說(shuō),都可以順著_Proto _這個(gè)屬性找到實(shí)例原型的屬性和方法。
舉例:
小結(jié):
一眼就看出來(lái)的缺點(diǎn)嘛!雖然方法可以共享,但是屬性沒(méi)有靈活性。一旦任何一個(gè)實(shí)例改變一個(gè)屬性,所有實(shí)例的值都會(huì)改變,不符合預(yù)期。
05
原型+構(gòu)造函數(shù)模式
顧名思義,這種模式結(jié)合了原型和構(gòu)造函數(shù)。構(gòu)造函數(shù)里添加屬性,利用原型的原理,在原型里添加方法,使其能共享方法。
舉例:
小結(jié):
確實(shí)是一個(gè)完美的解決方案,既解決了代碼的冗余現(xiàn)象可以批量創(chuàng)建對(duì)象,又可以共享方法!贊??!
06
Object.create()方法
Object.create()方法,是JavaScript內(nèi)置 Object 對(duì)象的標(biāo)準(zhǔn)方法。通過(guò)Object.create()創(chuàng)建的對(duì)象是全局對(duì)象Object的實(shí)例。這個(gè)是對(duì)第1種方式的一個(gè)拓展。
比如想創(chuàng)建的對(duì)象2與之前創(chuàng)建過(guò)的對(duì)象1的結(jié)構(gòu)等很相似,只是某些屬性有些不同,那么對(duì)象2就可以以對(duì)象1為原型創(chuàng)建對(duì)象。
舉例:
在控制臺(tái),我們可以看到:

為什么console.logg(per1)時(shí),只能看到name的值?因?yàn)閜er1是基于person為原型創(chuàng)建的,其它沒(méi)有變化的屬性必然在其原型鏈上:

所以能輸出per1.sex的屬性。:)
小結(jié):
方法是可以共享的噢!
07
ES6類(lèi)
ES6引入了一種創(chuàng)建JavaScript對(duì)象的新語(yǔ)法-class語(yǔ)法。class主法沒(méi)有給JavaScript添加新的邏輯,本質(zhì)上是一種語(yǔ)法糖。但體感很好。
舉例:
小結(jié):
與傳統(tǒng)的構(gòu)造函數(shù)創(chuàng)建的對(duì)象一樣,per1和per2就是Person的實(shí)例,方法并不是共享的。