深入理解JS原型鏈

前文:

繼承是OO(面向?qū)ο螅┱Z言中的一個最為人津津樂道的概念驻右。許多OO語言都支持兩種繼承方式:接口繼承和實(shí)現(xiàn)繼承。接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法摔敛。但在JS中函數(shù)沒有簽名,在ECMAScript中無法實(shí)現(xiàn)接口繼承全封,只支持實(shí)現(xiàn)繼承马昙,而且其實(shí)現(xiàn)繼承主要是依靠原型鏈來實(shí)現(xiàn)的。


要理解Javascript的繼承機(jī)制刹悴,必須從它的發(fā)展史說起行楞。
1994年,網(wǎng)景公司(Netscape)發(fā)布了Navigator瀏覽器0.9版颂跨。這是歷史上第一個比較成熟的網(wǎng)絡(luò)瀏覽器敢伸,轟動一時。網(wǎng)景公司急需一種網(wǎng)頁腳本語言恒削,使得瀏覽器可以與網(wǎng)頁互動池颈。工程師Brendan Eich負(fù)責(zé)開發(fā)這種新語言。他覺得钓丰,沒必要設(shè)計得很復(fù)雜躯砰,這種語言只要能夠完成一些簡單操作就夠了,比如判斷用戶有沒有填寫表單携丁。


Brendan Eich的選擇
如果真的是一種簡易的腳本語言琢歇,其實(shí)不需要有"繼承"機(jī)制。但是梦鉴,Javascript里面都是對象李茫,必須有一種機(jī)制,將所有對象聯(lián)系起來肥橙。所以魄宏,Brendan Eich最后還是設(shè)計了"繼承"。
但是存筏,他不打算引入"類"(class)的概念宠互,因?yàn)橐坏┯辛?類",Javascript就是一種完整的面向?qū)ο缶幊陶Z言了椭坚,這好像有點(diǎn)太正式了予跌,而且增加了初學(xué)者的入門難度。
他考慮到善茎,C++和Java語言都使用new命令券册,生成實(shí)例。
C++的寫法是:

 ClassName *object = new ClassName(param);

Java的寫法是:

Foo foo = new Foo();

因此,他就把new命令引入了Javascript汁掠,用來從原型對象生成一個實(shí)例對象略吨。但是,Javascript沒有"類"考阱,怎么來表示原型對象呢翠忠?
這時,他想到C++和Java使用new命令時乞榨,都會調(diào)用"類"的構(gòu)造函數(shù)(constructor)秽之。他就做了一個簡化的設(shè)計,在Javascript語言中吃既,new命令后面跟的不是類考榨,而是構(gòu)造函數(shù)。


prototype對象
prototype對象的引入:所有實(shí)例對象需要共享的屬性和方法鹦倚,都放在這個對象中河质,那些不需要共享的屬性和方法,就放在構(gòu)造函數(shù)中震叙。以此來模擬類掀鹅。

function Animal(name) {
    this.name = name
}

Animal.prototype.getName = function() {
    console.log(this.name)
}

var animal1 = new Animal('Kate')
var animal2 = new Animal('Lucy')

//對象animal1 和 animal2共享方法getName
animal1.getName()
animal2.getName()

proto寫入es6標(biāo)準(zhǔn)
當(dāng)一個對象被創(chuàng)建時,它的protp屬性和內(nèi)部屬性[[prototype]]指向相同的對象(也就是它的構(gòu)造函數(shù)的prototype屬性)媒楼。改變proto屬性的值同時也會改變內(nèi)部屬性[[prototype]]的值乐尊,除非該對象是不可擴(kuò)展的。
在ES5中划址,所有構(gòu)造函數(shù)的proto都指向Function.prototype
在ES6中扔嵌,構(gòu)造函數(shù)的proto指向它的父類構(gòu)造函數(shù)

obj.__proto__ === obj.[[prototype]]
// ES5
Cat.__proto__ === Function.prototype
// ES6
Cat.__proto__ === Animal

構(gòu)造函數(shù)繼承
有四種方式可以實(shí)現(xiàn)構(gòu)造函數(shù)的繼承
1.調(diào)用apply方法

function Animal() {
    this.species = '動物'
}
Animal.prototype.getName = function() {
    console.log('我是動物')
}

function Cat() {
    Animal.apply(this, arguments)
}
var cat = new Cat()
cat.species    // 動物
cat.getName()  // undefined

這種方法可以繼承父類構(gòu)造函數(shù)的屬性,但是無法繼承prototype屬性夺颤,即父類中共享的方法和屬性
2.改寫prototype對象

Cat.prototype = new Animal()
Cat.prototype.constructor = Cat

這是最常用的方法來模擬單繼承痢缎,缺點(diǎn)是始終要保留Animal的對象,如果Animal對象比較大時世澜,會消耗部分內(nèi)存(其實(shí)很少)独旷,并且沒有實(shí)現(xiàn)多繼承
3.直接繼承prototype

Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat

缺點(diǎn)是當(dāng)修改了Cat.prototype上的方法時會影響Animal.prototype
4.利用空對象作中介

var F = function(){}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat

缺點(diǎn)是無法繼承父類封裝的屬性

若要實(shí)現(xiàn)封裝屬性和共享同時繼承到子類中,就需要同時結(jié)合上面的1和4宜狐,請使用jqury的extend方法或者其他深拷貝方法势告。


繼承
關(guān)于繼承蛇捌, ES5和ES6的區(qū)別
ES5:先構(gòu)造子類的實(shí)例對象this抚恒,然后再將父類的方法添加到this上面
ES6:先創(chuàng)造父類的實(shí)例對象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this

// ES6
class Cat extends Animal {
    constructor() {
        super(this)
    }
    ...
}
// ES5
function Cat() {
    ...
}
Cat.prototype = new Animal()
Cat.prototype.constructor = Cat

參考文章:Javascript繼承機(jī)制的設(shè)計思想

本人學(xué)識有限 文章多有不足

若有錯誤 請大方指出 以免誤導(dǎo)他人

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末络拌,一起剝皮案震驚了整個濱河市俭驮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖混萝,帶你破解...
    沈念sama閱讀 212,949評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遗遵,死亡現(xiàn)場離奇詭異,居然都是意外死亡逸嘀,警方通過查閱死者的電腦和手機(jī)车要,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,772評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崭倘,“玉大人翼岁,你說我怎么就攤上這事∷竟猓” “怎么了琅坡?”我有些...
    開封第一講書人閱讀 158,419評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長残家。 經(jīng)常有香客問我榆俺,道長,這世上最難降的妖魔是什么坞淮? 我笑而不...
    開封第一講書人閱讀 56,812評論 1 285
  • 正文 為了忘掉前任茴晋,我火速辦了婚禮,結(jié)果婚禮上碾盐,老公的妹妹穿的比我還像新娘晃跺。我一直安慰自己,他們只是感情好毫玖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,927評論 6 386
  • 文/花漫 我一把揭開白布掀虎。 她就那樣靜靜地躺著,像睡著了一般付枫。 火紅的嫁衣襯著肌膚如雪烹玉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,102評論 1 291
  • 那天阐滩,我揣著相機(jī)與錄音二打,去河邊找鬼。 笑死掂榔,一個胖子當(dāng)著我的面吹牛继效,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播装获,決...
    沈念sama閱讀 39,171評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼瑞信,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了穴豫?” 一聲冷哼從身側(cè)響起凡简,我...
    開封第一講書人閱讀 37,921評論 0 268
  • 序言:老撾萬榮一對情侶失蹤逼友,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秤涩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帜乞,經(jīng)...
    沈念sama閱讀 44,366評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,675評論 2 327
  • 正文 我和宋清朗相戀三年筐眷,在試婚紗的時候發(fā)現(xiàn)自己被綠了黎烈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,820評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡匀谣,死狀恐怖怨喘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情振定,我是刑警寧澤必怜,帶...
    沈念sama閱讀 34,523評論 4 335
  • 正文 年R本政府宣布,位于F島的核電站后频,受9級特大地震影響梳庆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卑惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,162評論 3 317
  • 文/蒙蒙 一膏执、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧露久,春花似錦更米、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,885評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至消请,卻和暖如春栏笆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背臊泰。 一陣腳步聲響...
    開封第一講書人閱讀 32,126評論 1 267
  • 我被黑心中介騙來泰國打工蛉加, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缸逃。 一個月前我還...
    沈念sama閱讀 46,647評論 2 362
  • 正文 我出身青樓针饥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親需频。 傳聞我的和親對象是個殘疾皇子丁眼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,732評論 2 351

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