javascript原型與原型鏈

構(gòu)造函數(shù)與原型
與大部分面向?qū)ο笳Z言不同龄减,JavaScript中并沒有引入類(class)的概念,但JavaScript仍然大量地使用了對象班眯,為了保證對象之間的聯(lián)系希停,JavaScript引入了原型與原型鏈的概念。
在Java中署隘,聲明一個(gè)實(shí)例的寫法是這樣的:
ClassName obj = new ClassName()
復(fù)制代碼為了保證JavaScript“看起來像Java”宠能,JavaScript中也加入了new操作符:
var obj = new FunctionName()
復(fù)制代碼可以看到,與Java不同的是磁餐,JavaScript中的new操作符后面跟的并非類名而是函數(shù)名违崇,JavaScript并非通過類而是直接通過構(gòu)造函數(shù)來創(chuàng)建實(shí)例。
function Dog(name, color) {
this.name = name
this.color = color
this.bark = () => {
console.log('wangwang~')
}
}

const dog1 = new Dog('dog1', 'black')
const dog2 = new Dog('dog2', 'white')
復(fù)制代碼上述代碼就是聲明一個(gè)構(gòu)造函數(shù)并通過構(gòu)造函數(shù)創(chuàng)建實(shí)例的過程诊霹,這樣看起來似乎有點(diǎn)面向?qū)ο蟮臉幼恿诵哐樱珜?shí)際上這種方法還存在一個(gè)很大的問題。
在上面的代碼中脾还,有兩個(gè)實(shí)例被創(chuàng)建伴箩,它們有自己的名字、顏色鄙漏,但它們的bark方法是一樣的嗤谚,而通過構(gòu)造函數(shù)創(chuàng)建實(shí)例的時(shí)候,每創(chuàng)建一個(gè)實(shí)例怔蚌,都需要重新創(chuàng)建這個(gè)方法巩步,再把它添加到新的實(shí)例中。這無疑造成了很大的浪費(fèi)媚创,既然實(shí)例的方法都是一樣的渗钉,為什么不把這個(gè)方法單獨(dú)放到一個(gè)地方,并讓所有的實(shí)例都可以訪問到呢钞钙。

這里就需要用到原型(prototype):

每一個(gè)構(gòu)造函數(shù)都擁有一個(gè)prototype屬性鳄橘,這個(gè)屬性指向一個(gè)對象,也就是原型對象芒炼。當(dāng)使用這個(gè)構(gòu)造函數(shù)創(chuàng)建實(shí)例的時(shí)候瘫怜,prototype屬性指向的原型對象就成為實(shí)例的原型對象。
原型對象默認(rèn)擁有一個(gè)constructor屬性本刽,指向指向它的那個(gè)構(gòu)造函數(shù)(也就是說構(gòu)造函數(shù)和原型對象是互相指向的關(guān)系)鲸湃。
每個(gè)對象都擁有一個(gè)隱藏的屬性[[prototype]],指向它的原型對象子寓,這個(gè)屬性可以通過
Object.getPrototypeOf(obj) 或 obj.proto 來訪問暗挑。
實(shí)際上,構(gòu)造函數(shù)的prototype屬性與它創(chuàng)建的實(shí)例對象的[[prototype]]屬性指向的是同一個(gè)對象斜友,即 對象.proto === 函數(shù).prototype 炸裆。
如上文所述,原型對象就是用來存放實(shí)例中共有的那部分屬性鲜屏。
在JavaScript中烹看,所有的對象都是由它的原型對象繼承而來,反之洛史,所有的對象都可以作為原型對象存在惯殊。
訪問對象的屬性時(shí),JavaScript會(huì)首先在對象自身的屬性內(nèi)查找也殖,若沒有找到土思,則會(huì)跳轉(zhuǎn)到該對象的原型對象中查找。

那么可以將上述代碼稍微做些修改忆嗜,這里把bark方法放入Dog構(gòu)造函數(shù)的原型中:
function Dog(name, color) {
this.name = name
this.color = color
}

Dog.prototype.bark = () => {
console.log('wangwang~')
}
復(fù)制代碼接著再次通過這個(gè)構(gòu)造函數(shù)創(chuàng)建實(shí)例并調(diào)用它的bark方法:
const dog1 = new Dog('dog1', 'black')
dog1.bark() //'wangwang~'
復(fù)制代碼可以看到bark方法能夠正常被調(diào)用浪漠。這時(shí)再創(chuàng)建另一個(gè)實(shí)例并重寫它的bark方法,然后再次分別調(diào)用兩個(gè)實(shí)例的bark方法并觀察結(jié)果:
const dog2 = new Dog('dog2', 'white')
dog2.bark() = () => {
console.log('miaomiaomiao???')
}
dog1.bark() //'wangwang~'
dog2.bark() //'miaomiaomiao???'
復(fù)制代碼這里dog2重寫bark方法并沒有對dog1造成影響霎褐,因?yàn)樗貙慴ark方法的操作實(shí)際上是為自己添加了一個(gè)新的方法使原型中的bark方法被覆蓋了址愿,而并非直接修改了原型中的方法。若想要修改原型中的方法冻璃,需要通過構(gòu)造函數(shù)的prototype屬性:
Dog.prototype.bark = () => {
console.log('haha~')
}
dog1.bark() //'haha~'
dog2.bark() //'haha~'
復(fù)制代碼這樣看起來就沒什么問題了响谓,將實(shí)例中共有的屬性放到原型對象中,讓所有實(shí)例共享這部分屬性省艳。如果想要統(tǒng)一修改所有實(shí)例繼承的屬性娘纷,只需要直接修改原型對象中的屬性即可。而且每個(gè)實(shí)例仍然可以重寫原型中已經(jīng)存在的屬性來覆蓋這個(gè)屬性跋炕,并且不會(huì)影響到其他的實(shí)例赖晶。
原型鏈與繼承
上文提到,JavaScript中所有的對象都是由它的原型對象繼承而來。而原型對象自身也是一個(gè)對象遏插,它也有自己的原型對象捂贿,這樣層層上溯,就形成了一個(gè)類似鏈表的結(jié)構(gòu)胳嘲,這就是原型鏈(prototype chain)厂僧。
所有原型鏈的終點(diǎn)都是Object函數(shù)的prototype屬性,因?yàn)樵贘avaScript中的對象都默認(rèn)由Object()構(gòu)造了牛。Objec.prototype指向的原型對象同樣擁有原型颜屠,不過它的原型是null,而null則沒有原型鹰祸。
通過原型鏈就可以在JavaScript中實(shí)現(xiàn)繼承甫窟,JavaScript中的繼承相當(dāng)靈活,有多種繼承的實(shí)現(xiàn)方法蛙婴,這里只介紹一種最常用的繼承方法也就是組合繼承粗井。
function Dog(name, color) {
this.name = name
this.color = color
}

Dog.prototype.bark = () => {
console.log('wangwang~')
}

function Husky(name, color, weight) {
Dog.call(this, name, color)
this.weight = weight
}

Husky.prototype = new Dog()
復(fù)制代碼這里聲明了一個(gè)新的構(gòu)造函數(shù)Husky,通過call方法繼承Dog中的屬性(call方法的作用可以簡單理解為將Dog中的屬性添加到Husky中敬锐,因?yàn)檫€涉及到其他的知識(shí)點(diǎn)所以不多贅述)背传,并添加了一個(gè)weight屬性。然后用Dog函數(shù)創(chuàng)建了一個(gè)實(shí)例作為Husky的原型對象賦值給Husky.prototype以繼承方法台夺。這樣径玖,通過Husky函數(shù)創(chuàng)建的實(shí)例就擁有了Dog中的屬性和方法。
結(jié)語
如果想要深入了解關(guān)于JavaScript中的對象和原型鏈的話颤介,無腦推薦紅寶書(《JavaScript高級程序設(shè)計(jì)(第3版)》)吧梳星,第六章關(guān)于原型鏈有相當(dāng)詳細(xì)的講解。

作者:clancysong
鏈接:https://juejin.im/post/5a94c0de5188257a8929d837
來源:掘金
著作權(quán)歸作者所有滚朵。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)冤灾,非商業(yè)轉(zhuǎn)載請注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辕近,一起剝皮案震驚了整個(gè)濱河市韵吨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌移宅,老刑警劉巖归粉,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異漏峰,居然都是意外死亡糠悼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門浅乔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倔喂,“玉大人,你說我怎么就攤上這事∠” “怎么了班缰?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長班挖。 經(jīng)常有香客問我鲁捏,道長芯砸,這世上最難降的妖魔是什么萧芙? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮假丧,結(jié)果婚禮上双揪,老公的妹妹穿的比我還像新娘。我一直安慰自己包帚,他們只是感情好渔期,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渴邦,像睡著了一般疯趟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谋梭,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天信峻,我揣著相機(jī)與錄音,去河邊找鬼瓮床。 笑死盹舞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的隘庄。 我是一名探鬼主播踢步,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丑掺!你這毒婦竟也來了获印?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤街州,失蹤者是張志新(化名)和其女友劉穎兼丰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菇肃,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡地粪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琐谤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟆技。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出质礼,到底是詐尸還是另有隱情旺聚,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布眶蕉,位于F島的核電站砰粹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏造挽。R本人自食惡果不足惜碱璃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饭入。 院中可真熱鬧嵌器,春花似錦、人聲如沸谐丢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乾忱。三九已至讥珍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窄瘟,已是汗流浹背衷佃。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寞肖,地道東北人纲酗。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像新蟆,于是被迫代替她去往敵國和親觅赊。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

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

  • 前戲 寫的比較短了琼稻,三分鐘看完應(yīng)該是沒問題(嗯吮螺。。)帕翻。 當(dāng)然最好再花半小時(shí)思考理解一下鸠补。 正文 構(gòu)造函數(shù)與原型 與...
    clancysong閱讀 446評論 0 6
  • 一、數(shù)據(jù)類型JavaScript的數(shù)據(jù)類型可以分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型嘀掸。 基本數(shù)據(jù)類型(6種)StringN...
    qfstudy閱讀 369評論 1 0
  • 在JavaScript中紫岩,每個(gè)對象皆有原型。普通對象有_proto_(原型)屬性睬塌,創(chuàng)建的每一個(gè)函數(shù)有prot...
    七天_假閱讀 347評論 0 3
  • 在JavaScript這門語言中泉蝌,原型是一個(gè)非常非常重要的概念歇万,因?yàn)檫@門語言很特殊,不像其他面向?qū)ο笳Z言一樣是基于...
    前端王睿閱讀 504評論 1 12
  • 生活就是活著 過著 混著勋陪! 吃著 喝著 玩著贪磺!
    菲克閱讀 152評論 0 0