三分鐘看完JavaScript原型與原型鏈

前戲

  • 寫的比較短了嚼锄,三分鐘看完應(yīng)該是沒(méi)問(wèn)題(嗯肩民。。)蚪战。
  • 當(dāng)然最好再花半小時(shí)思考理解一下牵现。

正文

構(gòu)造函數(shù)與原型

與大部分面向?qū)ο笳Z(yǔ)言不同铐懊,JavaScript中并沒(méi)有引入類(class)的概念,但JavaScript仍然大量地使用了對(duì)象瞎疼,為了保證對(duì)象之間的聯(lián)系科乎,JavaScript引入了原型與原型鏈的概念。

在Java中贼急,聲明一個(gè)實(shí)例的寫法是這樣的:

ClassName obj = new ClassName()

為了保證JavaScript“看起來(lái)像Java”茅茂,JavaScript中也加入了new操作符:

var obj = new FunctionName()

可以看到,與Java不同的是太抓,JavaScript中的new操作符后面跟的并非類名而是函數(shù)名空闲,JavaScript并非通過(guò)類而是直接通過(guò)構(gòu)造函數(shù)來(lái)創(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')

上述代碼就是聲明一個(gè)構(gòu)造函數(shù)并通過(guò)構(gòu)造函數(shù)創(chuàng)建實(shí)例的過(guò)程走敌,這樣看起來(lái)似乎有點(diǎn)面向?qū)ο蟮臉幼恿瞬昵悖珜?shí)際上這種方法還存在一個(gè)很大的問(wèn)題。

在上面的代碼中悔常,有兩個(gè)實(shí)例被創(chuàng)建影斑,它們有自己的名字、顏色机打,但它們的bark方法是一樣的矫户,而通過(guò)構(gòu)造函數(shù)創(chuàng)建實(shí)例的時(shí)候,每創(chuàng)建一個(gè)實(shí)例残邀,都需要重新創(chuàng)建這個(gè)方法皆辽,再把它添加到新的實(shí)例中。這無(wú)疑造成了很大的浪費(fèi)芥挣,既然實(shí)例的方法都是一樣的驱闷,為什么不把這個(gè)方法單獨(dú)放到一個(gè)地方,并讓所有的實(shí)例都可以訪問(wèn)到呢空免。


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

  • 每一個(gè)構(gòu)造函數(shù)都擁有一個(gè)prototype屬性空另,這個(gè)屬性指向一個(gè)對(duì)象,也就是原型對(duì)象蹋砚。當(dāng)使用這個(gè)構(gòu)造函數(shù)創(chuàng)建實(shí)例的時(shí)候扼菠,prototype屬性指向的原型對(duì)象就成為實(shí)例的原型對(duì)象。
  • 原型對(duì)象默認(rèn)擁有一個(gè)constructor屬性坝咐,指向指向它的那個(gè)構(gòu)造函數(shù)(也就是說(shuō)構(gòu)造函數(shù)和原型對(duì)象是互相指向的關(guān)系)循榆。
  • 每個(gè)對(duì)象都擁有一個(gè)隱藏的屬性[[prototype]],指向它的原型對(duì)象墨坚,這個(gè)屬性可以通過(guò)
    Object.getPrototypeOf(obj)obj.__proto__ 來(lái)訪問(wèn)秧饮。
  • 實(shí)際上,構(gòu)造函數(shù)的prototype屬性與它創(chuàng)建的實(shí)例對(duì)象的[[prototype]]屬性指向的是同一個(gè)對(duì)象,即 對(duì)象.__proto__ === 函數(shù).prototype 盗尸。
  • 如上文所述柑船,原型對(duì)象就是用來(lái)存放實(shí)例中共有的那部分屬性。
  • 在JavaScript中泼各,所有的對(duì)象都是由它的原型對(duì)象繼承而來(lái)椎组,反之,所有的對(duì)象都可以作為原型對(duì)象存在历恐。
  • 訪問(wèn)對(duì)象的屬性時(shí)寸癌,JavaScript會(huì)首先在對(duì)象自身的屬性內(nèi)查找,若沒(méi)有找到弱贼,則會(huì)跳轉(zhuǎn)到該對(duì)象的原型對(duì)象中查找蒸苇。

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

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

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

接著再次通過(guò)這個(gè)構(gòu)造函數(shù)創(chuàng)建實(shí)例并調(diào)用它的bark方法:

const dog1 = new Dog('dog1', 'black')
dog1.bark()  //'wangwang~'

可以看到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???'

這里dog2重寫bark方法并沒(méi)有對(duì)dog1造成影響,因?yàn)樗貙慴ark方法的操作實(shí)際上是為自己添加了一個(gè)新的方法使原型中的bark方法被覆蓋了庇勃,而并非直接修改了原型中的方法檬嘀。若想要修改原型中的方法,需要通過(guò)構(gòu)造函數(shù)的prototype屬性:

Dog.prototype.bark = () => {
    console.log('haha~')
}
dog1.bark()  //'haha~'
dog2.bark()  //'haha~'

這樣看起來(lái)就沒(méi)什么問(wèn)題了责嚷,將實(shí)例中共有的屬性放到原型對(duì)象中鸳兽,讓所有實(shí)例共享這部分屬性。如果想要統(tǒng)一修改所有實(shí)例繼承的屬性罕拂,只需要直接修改原型對(duì)象中的屬性即可揍异。而且每個(gè)實(shí)例仍然可以重寫原型中已經(jīng)存在的屬性來(lái)覆蓋這個(gè)屬性,并且不會(huì)影響到其他的實(shí)例爆班。

原型鏈與繼承

上文提到衷掷,JavaScript中所有的對(duì)象都是由它的原型對(duì)象繼承而來(lái)。而原型對(duì)象自身也是一個(gè)對(duì)象柿菩,它也有自己的原型對(duì)象戚嗅,這樣層層上溯,就形成了一個(gè)類似鏈表的結(jié)構(gòu)枢舶,這就是原型鏈(prototype chain)懦胞。

所有原型鏈的終點(diǎn)都是Object函數(shù)的prototype屬性,因?yàn)樵贘avaScript中的對(duì)象都默認(rèn)由Object()構(gòu)造祟辟。Objec.prototype指向的原型對(duì)象同樣擁有原型医瘫,不過(guò)它的原型是null侣肄,而null則沒(méi)有原型旧困。

通過(guò)原型鏈就可以在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()

這里聲明了一個(gè)新的構(gòu)造函數(shù)Husky,通過(guò)call方法繼承Dog中的屬性(call方法的作用可以簡(jiǎn)單理解為將Dog中的屬性添加到Husky中拗盒,因?yàn)檫€涉及到其他的知識(shí)點(diǎn)所以不多贅述)怖竭,并添加了一個(gè)weight屬性。然后用Dog函數(shù)創(chuàng)建了一個(gè)實(shí)例作為Husky的原型對(duì)象賦值給Husky.prototype以繼承方法陡蝇。這樣痊臭,通過(guò)Husky函數(shù)創(chuàng)建的實(shí)例就擁有了Dog中的屬性和方法。

結(jié)語(yǔ)

如果想要深入了解關(guān)于JavaScript中的對(duì)象和原型鏈的話登夫,無(wú)腦推薦紅寶書(《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》)吧广匙,第六章關(guān)于原型鏈有相當(dāng)詳細(xì)的講解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恼策,一起剝皮案震驚了整個(gè)濱河市鸦致,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涣楷,老刑警劉巖分唾,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異狮斗,居然都是意外死亡绽乔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門碳褒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)迄汛,“玉大人,你說(shuō)我怎么就攤上這事骤视“鞍” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵专酗,是天一觀的道長(zhǎng)睹逃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)祷肯,這世上最難降的妖魔是什么沉填? 我笑而不...
    開(kāi)封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮佑笋,結(jié)果婚禮上翼闹,老公的妹妹穿的比我還像新娘。我一直安慰自己蒋纬,他們只是感情好猎荠,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布坚弱。 她就那樣靜靜地躺著,像睡著了一般关摇。 火紅的嫁衣襯著肌膚如雪荒叶。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天输虱,我揣著相機(jī)與錄音些楣,去河邊找鬼。 笑死宪睹,一個(gè)胖子當(dāng)著我的面吹牛愁茁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亭病,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼埋市,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了命贴?” 一聲冷哼從身側(cè)響起道宅,我...
    開(kāi)封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胸蛛,沒(méi)想到半個(gè)月后污茵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葬项,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年泞当,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片民珍。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡襟士,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嚷量,到底是詐尸還是另有隱情陋桂,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布蝶溶,位于F島的核電站嗜历,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏抖所。R本人自食惡果不足惜梨州,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望田轧。 院中可真熱鬧暴匠,春花似錦、人聲如沸傻粘。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至岛请,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間警绩,已是汗流浹背崇败。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肩祥,地道東北人后室。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像混狠,于是被迫代替她去往敵國(guó)和親岸霹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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