js創(chuàng)建對(duì)象的方法及其優(yōu)缺點(diǎn) JavaScript是面向?qū)ο筮€是基于對(duì)象?
JavaScript是面向?qū)ο筮€是基于對(duì)象?什么是面向?qū)ο笤诰幊痰氖澜缋?,有一種思想非常重要,那就是面向?qū)ο蟮乃季S。掌握了這個(gè)思路,就意味著你不再是一個(gè)程序員新手,開(kāi)始向開(kāi)發(fā)者的目標(biāo)邁進(jìn)了。那么,到底
JavaScript是面向?qū)ο筮€是基于對(duì)象?
什么是面向?qū)ο笤诰幊痰氖澜缋?,有一種思想非常重要,那就是面向?qū)ο蟮乃季S。掌握了這個(gè)思路,就意味著你不再是一個(gè)程序員新手,開(kāi)始向開(kāi)發(fā)者的目標(biāo)邁進(jìn)了。
那么,到底什么是面向?qū)ο蟮乃季S呢?說(shuō)到這,我可以告訴你這個(gè)東西的來(lái)歷。以前的編程是面向過(guò)程的。那么什么是面向過(guò)程的呢?之前在網(wǎng)上看到一句話,覺(jué)得形容的很好。讓我借一下。
一般來(lái)說(shuō),如果現(xiàn)在有人讓你把大象放進(jìn)冰箱,我們?nèi)绾斡妹嫦蜻^(guò)程的方法來(lái)做?我們可以把它分成以下幾個(gè)步驟:
1.打開(kāi)冰箱門(mén)。
2.把大象放進(jìn)冰箱。
3.關(guān)上冰箱門(mén)。
我們程序員會(huì)把這三個(gè)步驟寫(xiě)成三個(gè)函數(shù):
()
2.putElephantIntoFridge()
()
然后我們可以依次調(diào)用這些函數(shù)。嗯,你以為可以下班了,但是過(guò)幾天,你會(huì)發(fā)現(xiàn)這種需求會(huì)演變成很多奇怪的趨勢(shì),比如:
請(qǐng)把獅子放進(jìn)冰箱。
請(qǐng)把大象放進(jìn)微波爐里。
請(qǐng)把猴子放在微波爐里。
把其他動(dòng)物放在冰箱里,但是不要放。;不要關(guān)門(mén)。
5.……
諸如此類。這時(shí),要以面向過(guò)程的實(shí)現(xiàn)這些需求,就需要重新定義實(shí)現(xiàn)這些需求的功能。這無(wú)疑是一件令人抓狂的事情。但是老板和客戶出錢(qián)了,你就得做!所以你必須加班,所以你犧牲了你的工作...
所以,為了你的生活,你必須想出一個(gè)方法,不。;不需要每次需要時(shí)都重新定義實(shí)現(xiàn)的功能,也就是說(shuō),面向?qū)ο蟆?/p>
我們的想法是:如果每次我們想改變需求,我們不要 不要自己去做這些過(guò)程,而是指導(dǎo)別人去做,不是嗎?;沒(méi)關(guān)系嗎?所以我們面向?qū)ο笏季S的第一個(gè)轉(zhuǎn)變就是做一個(gè)執(zhí)行者,成為一個(gè)指揮者。
如果用定向思維來(lái)完成把大象放進(jìn)冰箱的需求。我們的方法變成這樣:
1.找到冰箱,命令冰箱自己打開(kāi)冰箱門(mén)。
2.找到大象,命令它自己進(jìn)入冰箱。
命令冰箱再次自行關(guān)門(mén)。
所以實(shí)現(xiàn)這個(gè)需求需要的實(shí)體是:大象和冰箱。我們把出現(xiàn)在實(shí)現(xiàn)需求中的實(shí)體稱為對(duì)象。大象要能自己進(jìn)入冰箱,冰箱要能自己開(kāi)關(guān)門(mén)。進(jìn)入冰箱、開(kāi)門(mén)和關(guān)門(mén)的能力,我們稱之為對(duì)象,通常用編程方法來(lái)表達(dá)。
所以總結(jié)一下:
1.面向過(guò)程是實(shí)現(xiàn)需求的第一步,任何工作都需要自己去做。
2.面向?qū)ο笠馕吨岩磺卸冀唤o能做的人。
所以現(xiàn)在的問(wèn)題是,如果有必要,當(dāng)求變變成上面說(shuō)的那些,如何解決面向?qū)ο蟮膯?wèn)題?我們現(xiàn)在要做的是分析需求中出現(xiàn)的對(duì)象(實(shí)體),然后賦予它們相應(yīng)的能力。
在新的需求中,大象、獅子和猴子應(yīng)該被放進(jìn)冰箱和微波爐。這時(shí),這里出現(xiàn)的物體(實(shí)體)是:動(dòng)物和容器。動(dòng)物需要的方法(能力)是進(jìn)入容器,容器需要的方法(能力)是開(kāi)關(guān)門(mén)。
因此,上述所有要求都可能變成:
1.[集裝箱]開(kāi)門(mén)。
2.[動(dòng)物]進(jìn)入[容器]。
3.關(guān)閉[容器](或者如果需要關(guān)門(mén),可以省略這一步)
所以這樣一來(lái),我們就不 不需要重復(fù)定義函數(shù)來(lái)實(shí)現(xiàn)這些需求。甚至在未來(lái),需求變成了把動(dòng)物從容器里拿出來(lái),我們只要在動(dòng)物物體上拓展把動(dòng)物從容器里拿出來(lái)的方法,就可以快速完成需求。這個(gè)時(shí)候,你犧牲工作的幾率就小多了。
如何實(shí)現(xiàn)面向?qū)ο?/p>
說(shuō)了這么多,大家大概也能明白什么是面向?qū)ο罅?。那么如何用js寫(xiě)代碼實(shí)現(xiàn)面向?qū)ο竽兀?/p>
在JavaScript中,我們使用構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象。
函數(shù)大象(){
}
大象會(huì)有一些獨(dú)特的數(shù)據(jù),比如它的體重、品種、年齡等等。我們稱這些獨(dú)特的數(shù)據(jù)為:屬性。每頭大象 的數(shù)據(jù)就不一樣了。這種差異在代碼中是如何體現(xiàn)的?
功能象(年齡、體重、類型){
}
我們將每個(gè)數(shù)據(jù)作為形式參數(shù)傳入構(gòu)造函數(shù),然后在創(chuàng)建時(shí)決定每個(gè)大象的實(shí)際數(shù)據(jù)。最終的構(gòu)造函數(shù)被寫(xiě)成:
功能象(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
}
現(xiàn)在,如果我們想要一頭大象,我們只需要用new的創(chuàng)建這個(gè)對(duì)象。
//這是一頭2歲重200kg的非洲象。
Var ele1新象(2,200kg,非洲象)
//這是一頭3歲的美國(guó)大象,體重250kg。
Var ele2新象(3,250kg,美國(guó)象)
現(xiàn)在大象有了,我們應(yīng)該教大象進(jìn)入容器的能力。這是方法。主要的編寫(xiě)方法是將這些方法編寫(xiě)到構(gòu)造函數(shù)中。
功能象(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
this.enterContainer函數(shù)(){}}
大象造好了,接下來(lái)要做的就是把冰箱變成一個(gè)物體。我們還為冰箱寫(xiě)了一個(gè)構(gòu)造函數(shù)。
功能冰箱(){
}
同樣,冰箱這個(gè)對(duì)象也有其獨(dú)特的屬性(數(shù)據(jù)),比如冰箱的高度和寬度。我們還將這些屬性寫(xiě)入構(gòu)造函數(shù)。
功能冰箱(寬、高){
寬度寬度
這個(gè)高度高度
}
現(xiàn)在根據(jù)需求,冰箱應(yīng)該有開(kāi)關(guān)門(mén)的方法,我們也寫(xiě)在構(gòu)造函數(shù)上。
功能冰箱(寬、高){
寬度寬度
這個(gè)高度高度
函數(shù)(){}
函數(shù)(){}
}
此時(shí),我們需要下面的代碼來(lái)完成 "把大象放進(jìn)冰箱 "
// 1找一個(gè)冰箱物體,這個(gè)物體的寬度和高度足以把大象放進(jìn)去。
var冰箱貼新款冰箱貼(4m,4m)
// 2給冰箱一個(gè)開(kāi)門(mén)指令。
()
// 3找到一個(gè)大象對(duì)象。
Var大象新象(2,200kg,非洲象)
// 4給大象下達(dá)指令進(jìn)入冰箱。
elephant.enterContainer()
// 5向冰箱發(fā)出關(guān)閉指令。
()
但是這個(gè)時(shí)候,我們要實(shí)現(xiàn)把獅子放進(jìn)冰箱的需求,就要寫(xiě)一段代碼,描述獅子的屬性和方法。而這個(gè)代碼幾乎和描述大象的代碼一模一樣。
功能獅子(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
this.enterContainer函數(shù)(){}
}
這時(shí)我們分析,無(wú)論大象、獅子、猴子的屬性(年齡、體重、各種類型)和方法(進(jìn)入容器)是否相同,這些都是我們需要的動(dòng)物,所以讓 讓我們直接寫(xiě)一個(gè)描述動(dòng)物的代碼。
功能動(dòng)物(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
this.enterContainer函數(shù)(){}
}
當(dāng)我們想把大象放進(jìn)冰箱時(shí):
Var ele新動(dòng)物(2,250kg,非洲象)
ele.enterContainer()
當(dāng)我們想把獅子放進(jìn)冰箱時(shí):
定義變量獅子新動(dòng)物(2250公斤,美洲獅)
lion.enterContainer()
此時(shí),不需要重復(fù)編寫(xiě)代碼來(lái)達(dá)到類似的要求。但這時(shí)有同學(xué)想說(shuō),動(dòng)物中猴子會(huì)爬樹(shù),大象會(huì) 如果要求猴子爬樹(shù),can 為什么我們不在動(dòng)物構(gòu)造器中增加一個(gè)爬樹(shù)的方法呢?這顯然是合理的!
當(dāng)然不是!在解決這個(gè)同學(xué)之前 的問(wèn)題,讓 讓我們做個(gè)總結(jié)。只是為了解決我們國(guó)家把動(dòng)物放進(jìn)冰箱的問(wèn)題,我們把面向過(guò)程的方法改成了面向?qū)ο蟮姆椒?。我們?cè)谏厦娴拇a中只使用了面向?qū)ο笏枷氲牡谝粋€(gè)特性:封裝。所謂封裝,就是把對(duì)象(需求中的實(shí)體)的屬性(特征)和方法(能力)抽象出來(lái),形成一個(gè)又一個(gè)的分類。在js中,es6之前沒(méi)有類的概念,所以我們用構(gòu)造函數(shù)來(lái)表示每個(gè)分類。抽象對(duì)象,只要你想用,就用構(gòu)造函數(shù)里的new操作,新建一個(gè)。
繼承
接下來(lái)解決猴子爬樹(shù)的問(wèn)題。當(dāng)然,要解決這個(gè)問(wèn)題,我們需要利用面向?qū)ο笏季S的另一個(gè)特性:繼承。繼承意味著子類可以享受父類的屬性和方法(從這里開(kāi)始不再解釋類似的屬性基本概念)。那么什么是子類和超類呢?為了解決把動(dòng)物放入冰箱的問(wèn)題,我們定義了一個(gè)動(dòng)物構(gòu)造器,我們理解為父類,然后提出這個(gè)問(wèn)題:不是所有的動(dòng)物都有相同的方法。猴子會(huì)爬樹(shù),但大象會(huì)。;t .這個(gè)時(shí)候我們需要重新定義猴子的構(gòu)造函數(shù)。我們把這種猴子理解為一個(gè)子類。
功能猴(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
函數(shù)(){}
this.enterContain:原型。讓 ■首先在控制臺(tái)中輸出一個(gè)構(gòu)造函數(shù):
console.dir(數(shù)組)
此時(shí),在控制臺(tái)中,我們可以看到數(shù)組構(gòu)造函數(shù)有一個(gè)prototype屬性。這個(gè)屬性就是我們所說(shuō)的原型。
通過(guò)擴(kuò)展這個(gè)原型屬性,我們發(fā)現(xiàn)通常使用的數(shù)組的方法都是從這個(gè)原型派生出來(lái)的。換句話說(shuō),原型方法可以由實(shí)例對(duì)象共享。
然后我們會(huì)用原型來(lái)解決猴子代碼重復(fù)太多的問(wèn)題。我們發(fā)現(xiàn)動(dòng)物構(gòu)造函數(shù)和猴子構(gòu)造函數(shù)都需要一個(gè)函數(shù)來(lái)進(jìn)入enterContainer。為了去掉這個(gè)重復(fù)的代碼,我們?cè)贏nimal這個(gè)相當(dāng)父類的構(gòu)造函數(shù)中聲明,將Monkey的原型指向Animal的一個(gè)實(shí)例。
功能動(dòng)物(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
this.enterContainer函數(shù)(){
Console.log(進(jìn)入容器)
}
}
功能猴(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
函數(shù)(){}
}
新動(dòng)物()
此時(shí),我們新建了一個(gè)Monkey實(shí)例,并發(fā)現(xiàn)這個(gè)實(shí)例可以調(diào)用容器方法。
Var猴新猴(2,25kg,金絲猴)
monkey.enterContainer()
此時(shí),進(jìn)入容器的方法enterContainer就可以共享了。然而,這種寫(xiě)作有一個(gè)缺點(diǎn)。我們寫(xiě)的方法都是寫(xiě)在構(gòu)造函數(shù)里的,每次新建對(duì)象都會(huì)在內(nèi)存里聲明一個(gè)函數(shù),而且這個(gè)函數(shù)的代碼每次都是一樣的。這是非常不必要的。
Var m1新款猴子(1,15kg,長(zhǎng)臂猴子)
Var m2新猴(2,25kg,獼猴)
console.log(m1,m2)
我們模仿原生js的,在原型上寫(xiě)方法來(lái)解決這個(gè)問(wèn)題。
功能動(dòng)物(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
}
函數(shù)(){
Console.log(進(jìn)入容器)
}功能猴(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
}
新動(dòng)物()
函數(shù)(){
Console.log(小猴子正在爬樹(shù))
}
首先從內(nèi)存分析,對(duì)象上沒(méi)有對(duì)象方法。
然后從控制臺(tái)觀察。
Var m1新款猴子(1,15kg,長(zhǎng)臂猴子)
Var m2新猴(2,25kg,獼猴)
console.log(m1,m2)
()
()
這是因?yàn)槲覀冊(cè)谠蜕蠈?xiě)方法,原型上的方法可以被實(shí)例共享。M1和m2都是猴子的實(shí)例,可以調(diào)用爬樹(shù)的方法。
利用構(gòu)造函數(shù)實(shí)現(xiàn)屬性繼承
到目前為止,我們已經(jīng)解決了一些代碼的重用問(wèn)題。我們發(fā)現(xiàn)有些代碼還是重復(fù)的,這部分代碼是對(duì)象的屬性。
在js中,我們可以使用借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)屬性的繼承。
什么是借款?這其實(shí)是一個(gè)所有函數(shù)都可以調(diào)用的方法:call方法。另一個(gè)功能是在函數(shù)執(zhí)行時(shí)修改這個(gè)點(diǎn)。舉個(gè)簡(jiǎn)單的例子:
函數(shù)fn(){
console.log(this)
}
fn()
這段代碼在正常情況下的結(jié)果是輸出窗口對(duì)象。
但是如果我們用借用的方法:
函數(shù)fn(){
consol:小明})
控制臺(tái)中的輸出是:我們正在使用call方法的第一個(gè)參數(shù)。利用這個(gè)特性,我們可以借用構(gòu)造函數(shù)。
具體代碼如下
功能動(dòng)物(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
}
功能猴(年齡、體重、類型){
(這個(gè),年齡,體重,類型)
}
至此,Monkey中重復(fù)的屬性代碼沒(méi)有了。那么讓我們 讓我們?cè)囋嘙onkey的一個(gè)實(shí)例是否會(huì)有這些屬性。
Var m1新款猴子(1,15kg,長(zhǎng)臂猴子)
Var m2新猴(2,25kg,獼猴)
console.log(m1,m2)
所以最后,我們的代碼是這樣寫(xiě)的
功能動(dòng)物(年齡、體重、類型){
年齡
這.魏重量輕
這種類型
}
函數(shù)(){
Console.log(進(jìn)入容器)
}
功能猴(年齡、體重、類型){
(這個(gè),年齡,體重,類型)
}
新動(dòng)物()
函數(shù)(){
Console.log(小猴子正在爬樹(shù))
}
這個(gè)時(shí)候,如果是所有動(dòng)物的方法,我們只需要回到世間。如果是猴子 我們將把它寫(xiě)在世界上。這就是js中實(shí)現(xiàn)定向的過(guò)程。我們把以上兩種實(shí)現(xiàn)繼承的稱為:組合繼承。
更簡(jiǎn)單的語(yǔ)法實(shí)現(xiàn)面向?qū)ο?/p>
上面寫(xiě)的是我們?cè)趀s5標(biāo)準(zhǔn)下的面向?qū)ο筮^(guò)程。這個(gè)過(guò)程有點(diǎn)麻煩。在es6的新標(biāo)準(zhǔn)下,我們有了更簡(jiǎn)單的語(yǔ)法來(lái)實(shí)現(xiàn)面向?qū)ο蟆?/p>
類別關(guān)鍵字
首先,讓我們 讓我們理解es6中的一個(gè)新關(guān)鍵字:class,它允許我們快速定義類。語(yǔ)法如下:
類別類別名稱{
}
然后在里面寫(xiě)這個(gè)類的構(gòu)造函數(shù)。
類別類別名稱{
構(gòu)造函數(shù)(){
}
}
例如,我們定義一個(gè)動(dòng)物類。
動(dòng)物類{
建造者(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
}
}
當(dāng)我想要一個(gè)動(dòng)物實(shí)例時(shí),我只需要新的。
Var a1新動(dòng)物(2,200kg,非洲象)
console.log(a1)
這個(gè)語(yǔ)法的本質(zhì)也是利用函數(shù)和原型來(lái)實(shí)現(xiàn)的,所以我想實(shí)現(xiàn)前面的動(dòng)物和冰箱的問(wèn)題,如果在這個(gè)新的語(yǔ)法中實(shí)現(xiàn)會(huì)更快。
擴(kuò)展關(guān)鍵字
在新語(yǔ)法的情況下,如果我們想實(shí)現(xiàn)繼承,我們只需要使用一個(gè)新的關(guān)鍵字 "擴(kuò)展 "。語(yǔ)法如下:
類子類擴(kuò)展父類{
構(gòu)造函數(shù)(){}
}
但重要的是,在這種新語(yǔ)法下實(shí)現(xiàn)的繼承,必須先在子類的構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù)。
類子類擴(kuò)展父類{
構(gòu)造函數(shù)(){
超級(jí)()
}
}
所以現(xiàn)在要認(rèn)識(shí)到Mokey 從動(dòng)物的遺傳,我們不得不這樣寫(xiě)。
動(dòng)物類{
建造者(年齡、體重、類型){
年齡
這個(gè)重量重量
這種類型
}
enterContainer(){
Console.log(進(jìn)入容器)
}
}
類Mokey擴(kuò)展動(dòng)物{
建造者(年齡、體重、類型){
超級(jí)(年齡、體重、類型)
}
climbingTree(){
Consol
javascript怎么實(shí)現(xiàn)像其他語(yǔ)言一樣,一個(gè)類一個(gè)文件?應(yīng)該注意哪些問(wèn)題?
我不 不知道有沒(méi)有學(xué)過(guò)java,就每個(gè)類寫(xiě)一個(gè)文件,單獨(dú)介紹一下。建議看看JavaScript面向?qū)ο缶幊?。網(wǎng)上有很多專門(mén)介紹的文章,很全面,所以我贏了 不要在這里張貼代碼。