徹底弄懂原型、原型鏈以及繼承

javascript在創(chuàng)建一個(gè)對(duì)象的時(shí)候余爆,默認(rèn)會(huì)為該對(duì)象創(chuàng)建一個(gè)prototype的屬性,該屬性的值是一個(gè)對(duì)象夸盟,即創(chuàng)建對(duì)象的原型蛾方。

下面我們通過(guò)一個(gè)例子了解原型的特性:

function Person(){

}

Person.prototype.name="tom"

var person1 = new Person()

console.log(person1.name) //tom

var person2 = new Person()

console.log(person2.name) //tom

上面的例子中,構(gòu)造函數(shù)Person的原型對(duì)象有一個(gè)自定義屬性name

所有的實(shí)例共享同一個(gè)原型對(duì)象,所以打印person1.name和person2.name都是tom

構(gòu)造函數(shù)上陕、原型和實(shí)例的關(guān)系:

每一個(gè)構(gòu)造函數(shù)(函數(shù)對(duì)象)都有一個(gè)prototype屬性桩砰,指向函數(shù)的原型對(duì)象;每一個(gè)原型對(duì)象都有一個(gè)constructor屬性释簿,指向構(gòu)造函數(shù)五芝;每一個(gè)實(shí)例都有一個(gè)__proto__屬性,指向構(gòu)造函數(shù)的原型對(duì)象

那么原型對(duì)象辕万、prototype對(duì)象、實(shí)例對(duì)象之間的關(guān)系圖下圖所示


上圖中prototype對(duì)象也是一個(gè)實(shí)例對(duì)象沉删,他也有自己的原型對(duì)象渐尿,默認(rèn)原型的構(gòu)造函數(shù)是Object,加上prototype對(duì)象關(guān)系圖如下:

接下來(lái)我們來(lái)說(shuō)一下繼承

1.原型鏈繼承

function?Animal()?{

??this.sleep?=?function()?{

????console.log('睡覺(jué)')

??}

}

function?Person(name)?{

??this.name?=?name

}

Person.prototype?=?new?Animal()

var?liming?=?new?Person('liming')

console.log(liming.name)

liming.sleep()

打印結(jié)果

2

睡覺(jué)

上述例子中矾瑰,改變了Person構(gòu)造函數(shù)的原型指向砖茸,從而實(shí)現(xiàn)了繼承,讓Person的實(shí)例liming擁有了sleep的方法殴穴。上述例子的圖解如下:


缺點(diǎn):如果Animal實(shí)例中有引用類(lèi)型的變量凉夯,這個(gè)引用變量被所有實(shí)例共享,一個(gè)實(shí)例更改之后會(huì)影響其他實(shí)例

如果我們將代碼改成

function?Animal()?{

??this.todoList?=?['坐車(chē)',?'開(kāi)會(huì)',?'吃飯',?'回家']

??this.sleep?=?function()?{

????console.log('睡覺(jué)')

??}

}

function?Person(name)?{

??this.name?=?name

}

Person.prototype?=?new?Animal()

var?liming?=?new?Person('liming')

console.log(liming.name)

liming.todoList.splice(1,?1)

var?tom?=?new?Person('tom')

console.log(tom.todoList)


可以看到liming的代辦去掉了開(kāi)會(huì)采幌,tom的代辦的開(kāi)會(huì)也沒(méi)有了劲够。而且沒(méi)辦法給Animal傳遞實(shí)例參數(shù)。所以有了構(gòu)造函數(shù)繼承

二休傍、構(gòu)造函數(shù)繼承

構(gòu)造函數(shù)繼承就是在子類(lèi)的構(gòu)造函數(shù)中執(zhí)行父類(lèi)的構(gòu)造函數(shù)征绎,并使用call改變父類(lèi)的this指向子類(lèi),還可以使用call傳遞參數(shù)磨取,實(shí)現(xiàn)實(shí)例屬性人柿,具體代碼如下

function?Animal(sort)?{

??this.sort?=?sort

??this.todoList?=?['坐車(chē)',?'開(kāi)會(huì)',?'吃飯',?'回家']

??this.sleep?=?function()?{

????console.log('睡覺(jué)')

??}

}

function?Person(name,?sort)?{

??Animal.call(this,?sort)

??this.name?=?name

}

var?liming?=?new?Person('liming',?'people')

liming.todoList.splice(1,?1)

console.log('liming的todolist',?liming.todoList)

var?tom?=?new?Person('tom',?'people')

console.log(tom.sort)

console.log('tom的todolist',?tom.todoList)


? ? 結(jié)果展示:

上述例子在Person的構(gòu)造函數(shù)中執(zhí)行了Animal.call(this,sort)? 執(zhí)行力Animal構(gòu)造函數(shù)的代碼,并把this忙厌,指向當(dāng)前person實(shí)例凫岖,所以liming去掉了開(kāi)會(huì)日程,但是并不影響tom的代辦列表逢净。

原型關(guān)系圖解:(這個(gè)例子Person的原型指向并沒(méi)有改變哥放,只是把Person的代碼拿來(lái)執(zhí)行了一遍歼指。)


缺點(diǎn):

這種方法的缺點(diǎn)顯而易見(jiàn),沒(méi)有實(shí)現(xiàn)繼承婶芭。

三东臀、原型構(gòu)造函數(shù)組合繼承

function?Animal(sort)?{

??this.sort?=?sort

??this.todoList?=?['坐車(chē)',?'開(kāi)會(huì)',?'吃飯',?'回家']

??this.sleep?=?function()?{

????console.log('睡覺(jué)')

??}

}

Animal.prototype.saySort?=?function()?{

??console.log(this.sort)

}

function?Person(name,?sort)?{

??Animal.call(this,?sort)

??this.name?=?name

}

Person.prototype?=?new?Animal()

var?liming?=?new?Person('liming',?'people')

liming.todoList.splice(1,?1)

console.log('liming的todolist',?liming.todoList)

var?tom?=?new?Person('tom',?'people')

tom.saySort()

顧名思義是前兩種方式的結(jié)合,在構(gòu)造函數(shù)的基礎(chǔ)上使用Person.prototype?=?new?Animal() 改變Person的prototype的指向犀农。從而是可以訪問(wèn)Animal原型上的方法saySort()

關(guān)系圖解:


可以清晰的看到 liming和tom都有自己的todolist 所以不會(huì)去原型上查找todolist屬性惰赋。

這種方法的缺點(diǎn):

每個(gè)實(shí)例都有一份自己的屬性,原型上也有一份屬性呵哨,雖然實(shí)例上有就不會(huì)去原型上查找赁濒,但是這種方法原型上的屬性和方法就沒(méi)有用,有些多余孟害。

4.原型式繼承

創(chuàng)建一個(gè)名為F的構(gòu)造函數(shù)拒炎,把 F的prototype設(shè)置為傳進(jìn)來(lái)的對(duì)象

var?person?=?{

??name:?'tom',

??sayName:?function()?{

????console.log(this.name)

??}

}

function?object(obj)?{

??function?F()?{}

??F.prototype?=?obj

??return?new?F()

}

var?person1?=?object(person)

person1.name?=?'jerry'

person1.sayName()

var?person2?=?object(person)

person2.name?=?'jack'

person1.sayName()

打印結(jié)果:


結(jié)果很明顯所有實(shí)例共享原型屬性

關(guān)系圖解:


缺點(diǎn):所有實(shí)例共享原型,而且沒(méi)有自己的實(shí)例屬性挨务。

5.寄生式繼承

在原型式繼承的基礎(chǔ)上击你,封裝原型式繼承

function?create(obj,?suject)?{

??var?example?=?Object(obj)

??example.suject?=?suject

??return?example

}

var?person?=?{

??name:?'tom',

??sayName:?function()?{

????console.log(this.name)

??}

}

var?person1?=?create(person,?'游泳')

console.log(person1.suject)

person1.name?=?'jerry'

var?person2?=?create(person,?'拳擊')

console.log(person2.suject)

person2.sayName()

打印結(jié)果如下:


顯而易見(jiàn),person1和person2擁有了自己的實(shí)例屬性谎柄,

Object(person) 的作用等同于原型式繼承 把person作為構(gòu)造函數(shù)的原型丁侄,所有的實(shí)例共享person的屬性和方法

6.寄生組合式繼承

就是把寄生式繼承和組合式繼承結(jié)合起來(lái)

function?inherite(parent,?child)?{

??var?pro?=?Object.create(parent.prototype)

??pro.construct?=?child

??child.prototype?=?pro

}

function?Animal(sort)?{

??this.sort?=?sort

??this.todoList?=?['坐車(chē)',?'開(kāi)會(huì)',?'吃飯',?'回家']

??this.sleep?=?function()?{

????console.log('睡覺(jué)')

??}

}

Animal.prototype.saySort?=?function()?{

??console.log(this.sort)

}

function?Person(name,?sort)?{

??Animal.call(this,?sort)

??this.name?=?name

}

inherite(Animal,?Person)

var?liming?=?new?Person('liming',?'people')

liming.todoList.splice(1,?1)

console.log('liming的todolist',?liming.todoList)

var?tom?=?new?Person('tom',?'people')

tom.saySort()

console.log('tom的todolist',?tom.todoList)


打印結(jié)果


關(guān)系圖解:


這種方式就避免了再次創(chuàng)建Animal實(shí)例,sort todolist? sleep等屬性和方法也只存在在實(shí)例上朝巫,原型上已經(jīng)沒(méi)有了鸿摇。

大多數(shù)的繼承都采用這種方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劈猿,一起剝皮案震驚了整個(gè)濱河市拙吉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揪荣,老刑警劉巖筷黔,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異仗颈,居然都是意外死亡必逆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)揽乱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)名眉,“玉大人,你說(shuō)我怎么就攤上這事凰棉∷鹇#” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵撒犀,是天一觀的道長(zhǎng)福压。 經(jīng)常有香客問(wèn)我掏秩,道長(zhǎng),這世上最難降的妖魔是什么荆姆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任蒙幻,我火速辦了婚禮,結(jié)果婚禮上胆筒,老公的妹妹穿的比我還像新娘邮破。我一直安慰自己,他們只是感情好仆救,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布抒和。 她就那樣靜靜地躺著,像睡著了一般彤蔽。 火紅的嫁衣襯著肌膚如雪摧莽。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天顿痪,我揣著相機(jī)與錄音镊辕,去河邊找鬼。 笑死蚁袭,一個(gè)胖子當(dāng)著我的面吹牛丑蛤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播撕阎,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼碌补!你這毒婦竟也來(lái)了虏束?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤厦章,失蹤者是張志新(化名)和其女友劉穎镇匀,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體袜啃,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汗侵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了群发。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晰韵。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖熟妓,靈堂內(nèi)的尸體忽然破棺而出雪猪,到底是詐尸還是另有隱情,我是刑警寧澤起愈,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布只恨,位于F島的核電站译仗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏官觅。R本人自食惡果不足惜纵菌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望休涤。 院中可真熱鬧咱圆,春花似錦、人聲如沸滑绒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疑故。三九已至杠览,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纵势,已是汗流浹背踱阿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钦铁,地道東北人软舌。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像牛曹,于是被迫代替她去往敵國(guó)和親佛点。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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