學(xué)習(xí)JavaScript中的原型鏈?zhǔn)嚼^承

最近在學(xué)習(xí)JavaScript的面向?qū)ο螅籧onstructor,prototype和_proto_搞到頭大,但還好,磕磕絆碰碰,終于了解了一點(diǎn)原型繼承。接下來(lái)我們來(lái)看看這個(gè)原型繼承是怎么回事

一、關(guān)于原型的幾個(gè)概念

  1. prototype屬性
  2. _proto_屬性
  3. constructor屬性

他們直觀的關(guān)系是:

function/
    |——prototype/
              |—— constructor
              |—— __proto__
prototype屬性

任何一個(gè)函數(shù)都存在著這樣的一個(gè)prototype屬性,這個(gè)屬性是一個(gè)對(duì)象仙蚜,稱為原型對(duì)象艳丛。這個(gè)原型對(duì)象里有自函數(shù)一創(chuàng)建就生成的兩個(gè)屬性一個(gè)是constructor和 _proto_,除此之外我們可以給這個(gè)對(duì)象添加屬性和方法,就像給一個(gè)普通對(duì)象動(dòng)態(tài)添加屬性和方法那樣

example:
    //創(chuàng)建基類(或叫超類或叫父類)
    function Person(){};
    Person.prototype.name = 'kuohao';
    Person.prototype.age = 21;
    Person.prototype.method = function (){
        return this.name +':'+ this.age;
    }
    //給Person構(gòu)造函數(shù)的原型對(duì)象添加一些屬性和方法
    //(為什么說(shuō)它是構(gòu)造函數(shù)呢袭厂,因?yàn)樾枰脕?lái)構(gòu)造對(duì)象橄杨,實(shí)際上跟普通函數(shù)一樣)

現(xiàn)在原型對(duì)象就多了兩個(gè)屬性和一個(gè)方法

Person/
    |——prototype/
              |—— constructor
              |—— __proto__
              |——name:'kuhao'
              |——age:21
              |——method:function(){
                      return……
                     〈狭}

這個(gè)原型對(duì)象有啥用惯悠?鸭蛙?寝凌?
請(qǐng)看——

//實(shí)例化
var guy1 = new Person();
var guy2 = new Person();

console.log(guy1.name);    //'kuohao'
console.log(guy2.name);    //'kuohao'  

guy1.method()    //'kuohao':21
guy2.method()    //'kuohao':21

我們沒(méi)有給他們定義屬性和方法伐债,他們繼承了Person構(gòu)造函數(shù)原型對(duì)象里面的屬性和方法祖今,注意我們也沒(méi)給Person構(gòu)造函數(shù)定義屬性和方法噢

咋一看邪驮,跟構(gòu)造函數(shù)和工廠模式差不多喻粹,他們都生成擁有相同屬性和方法的對(duì)象型酥。但是原型對(duì)象生成的對(duì)象有一個(gè)很重要的特點(diǎn)就是他們共用一個(gè)原型對(duì)象的屬性和方法查乒。

為什么這么說(shuō)呢?
使用布爾運(yùn)算來(lái)驗(yàn)證一下就知道了

guy1.method()===guy2.method;    //true

如果是構(gòu)造函數(shù)生成的對(duì)象州弟,他們的方法都不相等潭陪,原因就是構(gòu)造函數(shù)生成的對(duì)象有不同的引用的地址,而構(gòu)造函數(shù)的原型繼承方法生成的對(duì)象指向了同一個(gè)引用地址慷嗜,他們的對(duì)象都使用這個(gè)引用地址的屬性和方法菌赖,所以他們的方法是相等的辕羽,對(duì)于生成的對(duì)象的new方法绰寞,在另外一篇文章會(huì)講到他炊。


_proto_屬性

這是相當(dāng)重要的一個(gè)屬性涩笤,但是它不是標(biāo)準(zhǔn)屬性俏脊,在標(biāo)準(zhǔn)中全谤,它是不對(duì)外開(kāi)放的,當(dāng)時(shí)chrome和Firefox的私有屬性中對(duì)外暴露了它爷贫,使得我們可以比較清楚了了解原型繼承的過(guò)程认然。

__proto__

_proto_這個(gè)屬性可以讓我們?cè)L問(wèn)創(chuàng)建當(dāng)前對(duì)象的構(gòu)造函數(shù)的prototype原型對(duì)象。那么當(dāng)我們調(diào)用guy1.method()方法的時(shí)候漫萄,其實(shí)是這樣的:

  1. 當(dāng)js解析器解析guy1.method()的時(shí)候卷员,先看看guy1對(duì)象實(shí)例里有沒(méi)有method這個(gè)方法
    js解析器問(wèn):"喂,哥們腾务,你的method方法呢?"
    guy1說(shuō):"這個(gè)方法是我老爸的毕骡,不在我這里"
    js解析器問(wèn):“怎么找到你老爸?”
    guy1指著_proto_說(shuō):“這里有道門(mén),你進(jìn)去就可以找到他了”

2.然后js解析器就又跑去找他老豆未巫,找到他老豆后
問(wèn):“喂喂窿撬,你兒子叫我來(lái)找method方法,在哪叙凡?”
guy1的老豆Person就拿出一個(gè)箱子(prototype)劈伴,說(shuō):“method方法就在里面,你拿去吧握爷!”

如果Person父類還是沒(méi)找到method方法的話跛璧,實(shí)際上它的prototype對(duì)象也有一個(gè)_proto_屬性,可以訪問(wèn)guy1的爺爺類的prototype對(duì)象饼拍,找到method方法赡模。

所以,這個(gè)查找是一環(huán)接一環(huán)的师抄,就像遞歸一樣漓柑。

![原型鏈,圖片來(lái)自慕課網(wǎng)].PNG](http://upload-images.jianshu.io/upload_images/1577855-21c757167154f75a.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

constructor屬性

constructor屬性指向的是創(chuàng)建此對(duì)象的構(gòu)造函數(shù)的引用叨吮,這個(gè)屬性存在prototype原型對(duì)象中辆布,構(gòu)造函數(shù)的對(duì)象實(shí)例也可以通過(guò)constructor屬性來(lái)訪問(wèn)構(gòu)造它的那個(gè)函數(shù)。

構(gòu)造與原型

這個(gè)屬性對(duì)于原型繼承的實(shí)現(xiàn)來(lái)說(shuō)茶鉴,不是很重要锋玲。

二、原型繼承的實(shí)現(xiàn)

    //父類
    function Person(){};
    Person.prototype.method = function (){
        return 'hello';
    }

    //子類
    function Child(){};
    Child.prototype = Object.create(Person.prototype);
    Child.prototype.constructor = Child;
    Child.prototype.say = function (){
        return 'hello world';
    }
    
    var c1 = new Child();
    c1.method();    //'hello'
    c1.say();       //'hello world'
    //由此可見(jiàn)子類繼承了父類的方法涵叮,也擁有自己的方法
Object.create()方法

Object.create()方法是ES5的一個(gè)用來(lái)創(chuàng)建一個(gè)指定原型和若干指定屬性的對(duì)象的方法惭蹂。
定義來(lái)自 Mozilla開(kāi)發(fā)者文檔

Child.prototype = Object.create(Person.prototye);

這句話的含義就是創(chuàng)建一個(gè)以Person原型對(duì)象為原型的空對(duì)象,賦值給Child的prototype原型對(duì)象.

Object.create(Person.prototye),相當(dāng)與創(chuàng)建了這樣一個(gè)對(duì)象:

{
    constructor
    //指向Person構(gòu)造函數(shù)割粮,這就是為什么上面要把這個(gè)屬性指回Child的原因
    __proto__
    //指向Person.prototype盾碗,上面說(shuō)到原型鏈繼承正是通過(guò)這個(gè)屬性層層查找實(shí)現(xiàn)的
}

將這個(gè)對(duì)象去覆蓋Child子類的prototype,這就成功與Person父類搭上了關(guān)系再此之前舀瓢,Person與Child沒(méi)任何關(guān)系廷雅。


但是Object.create()這個(gè)方法是新方法,低級(jí)的瀏覽器京髓,如IE9以下不支持航缀,需要做一下兼容處理

examle:
    
        function createObejct(o){
            if(!Object.create){
                //新建一個(gè)構(gòu)造函數(shù),用來(lái)做臨時(shí)對(duì)象
                function a(){};
                //把原型對(duì)象參數(shù)賦給這個(gè)空對(duì)象的原型對(duì)象
                a.prototype = o;
                return new a();
                //實(shí)例化一個(gè)出來(lái)一個(gè)原型對(duì)象指向原型對(duì)象參數(shù)的空對(duì)象堰怨,返回給上下文
            }else{
                return Object.create(o);
                //直接使用
            }
        }
Object.create的一些替代方法
  1. 直接將Person.prototype賦值給Child.prototype

Child.prototype = Person.prototype

這樣Person和Child就共用一個(gè)原型對(duì)象芥玉,他們的屬性和方法都是一樣的,但是這個(gè)就有問(wèn)題了备图,如果Child類想擴(kuò)展自己的屬性和方法飞傀,那么Person類也會(huì)受到影響皇型。

這里要注意的是賦一個(gè)原型對(duì)象為Person.prototype的空對(duì)象(上面的方法)跟賦一個(gè)Person.prototype是不一樣的。

前者Child.prototype指向空對(duì)象的引用再由空對(duì)象中的_proto_\指向Person.prototype砸烦,后者Child.prototype直接指向Person.prototype引用弃鸦,后續(xù)的修改在都Person.prototype上,因?yàn)樗麄児灿靡粋€(gè)原型對(duì)象。

前者
后者

所以這個(gè)方法是非常不可取的幢痘,跟面向?qū)ο蟮亩鄳B(tài)特性相悖

2.new 一個(gè)Person的對(duì)象實(shí)例賦給Child的原型對(duì)象

Child.prototype = new Person()

這貌似是一個(gè)不錯(cuò)的方法唬格,但是它也有弊端,就是事實(shí)上我們常常不會(huì)使用一個(gè)空的構(gòu)造函數(shù)颜说,來(lái)實(shí)例化對(duì)象购岗,我們往往會(huì)將構(gòu)造函數(shù)繼承和原型繼承結(jié)合在一起,所以我們的構(gòu)造函數(shù)往往會(huì)有一些實(shí)例屬性和實(shí)例方法门粪,如果new Person()出來(lái)一個(gè)實(shí)例對(duì)象喊积,對(duì)象里面還夾帶著一些實(shí)例屬性和方法,這看起來(lái)非常怪玄妈,雖然也是一個(gè)指向Person.prototype的對(duì)象乾吻。所以這種方法也不推薦使用,應(yīng)該使用 Object.create() 較為妥當(dāng).

總結(jié):

我個(gè)人覺(jué)得實(shí)現(xiàn)原型繼承最重要就是兩個(gè)屬性的理解拟蜻,prototype原型對(duì)象和_proto_這個(gè)接口的概念的理解绎签,再結(jié)合原型鏈層層查找這種繼承方式的直觀感知,就能比較好地掌握原型式繼承酝锅。我也是這兩天才理解的原型鏈?zhǔn)嚼^承诡必,如果有所繆誤,請(qǐng)批評(píng)指正搔扁!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爸舒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子稿蹲,更是在濱河造成了極大的恐慌扭勉,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件场绿,死亡現(xiàn)場(chǎng)離奇詭異剖效,居然都是意外死亡嫉入,警方通過(guò)查閱死者的電腦和手機(jī)焰盗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咒林,“玉大人熬拒,你說(shuō)我怎么就攤上這事〉婢海” “怎么了澎粟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵蛀序,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我活烙,道長(zhǎng)徐裸,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任啸盏,我火速辦了婚禮重贺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘回懦。我一直安慰自己气笙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布怯晕。 她就那樣靜靜地躺著潜圃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舟茶。 梳的紋絲不亂的頭發(fā)上谭期,一...
    開(kāi)封第一講書(shū)人閱讀 49,729評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音稚晚,去河邊找鬼崇堵。 笑死,一個(gè)胖子當(dāng)著我的面吹牛客燕,可吹牛的內(nèi)容都是我干的鸳劳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼也搓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赏廓!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起傍妒,我...
    開(kāi)封第一講書(shū)人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤幔摸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后颤练,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體既忆,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年嗦玖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了患雇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宇挫,死狀恐怖苛吱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情器瘪,我是刑警寧澤翠储,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布绘雁,位于F島的核電站,受9級(jí)特大地震影響援所,放射性物質(zhì)發(fā)生泄漏庐舟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一住拭、第九天 我趴在偏房一處隱蔽的房頂上張望继阻。 院中可真熱鬧,春花似錦废酷、人聲如沸瘟檩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)墨辛。三九已至,卻和暖如春趴俘,著一層夾襖步出監(jiān)牢的瞬間睹簇,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工寥闪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留太惠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓疲憋,卻偏偏與公主長(zhǎng)得像凿渊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缚柳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

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