手撕js中的繼承(二)

原型鏈的缺陷

1.引用類型的值在原型鏈傳遞中存在的問題
js中有簡單數(shù)據(jù)類型和引用數(shù)據(jù)類型(復雜數(shù)據(jù)類型),引用類型的值有一個特點:在賦值的時候猴伶,傳遞給變量的其實是它在內(nèi)存當中的地址。被賦值完的變量相當于一個指針膛壹。這樣一來就有大問題了拣帽,上代碼:

function Father() {
  this.name = 'father';
  this.hobby = ['sport', 'read'];
}

function Son() {

}
Son.prototype = new Father();

let son1 = new Son();
let son2 = new Son();
console.log(son1.name);
console.log(son2.name);
console.log(son1.hobby);
console.log(son2.hobby);

打印如下:

接著我們修改一下son1的hobby和name屬性看看:

son1.name = 'son';
son1.hobby.push('play games');
console.log(son1);
console.log(son2);
console.log(son2.name);
console.log(son1.hobby);
console.log(son2.hobby);

打印結(jié)果如下:

這下就有問題了,我們修改了son1的hobby和name屬性玲躯,但是son2的name屬性是不變的据德,hobby屬性發(fā)生了改變。我們嘗試想一下:
(1).son1和son2有自己的hobby屬性嗎跷车?
沒有棘利!只是Son的原型對象上有hobby屬性,因為我修改了指向朽缴,指向了Father的實例赡译,son1和son2其實是通過__proto__屬性訪問Son的原型對象上的hobby屬性,從而訪問和操作數(shù)組的不铆。
(2).son1和son2有自己的name屬性嗎蝌焚?
開始都沒有,但是后來我們手動給son1添加了name屬性誓斥,相當于son1就有了只洒,但是son2依然沒有name屬性
所以在原型鏈中如果Father含有引用類型的值,那么子類型的實例共享這個引用類型的值劳坑,也就是上面的hobby數(shù)組毕谴,這就是原型鏈的第一個缺陷。

2.第二個缺陷是:在創(chuàng)建子類型的實例時距芬,是無法向父類型的構(gòu)造函數(shù)中傳遞參數(shù)的涝开,在上面的例子中,如果Fathername屬性是要傳遞數(shù)的框仔,而不是寫死的舀武,那么我們在實例化son1和son2的時候根本沒辦法傳參。

借用構(gòu)造函數(shù)繼承

為了解決引用類型值帶來的問題离斩,我們采用借用構(gòu)造函數(shù)繼承的方式银舱,它的核心思路是:在子類型的構(gòu)造函數(shù)中調(diào)用父類型的構(gòu)造函數(shù),這里需要借助call()或者apply()方法跛梗,具體代碼如下:

function Father() {
  this.name = 'father';
  this.hobby = ['sport', 'read'];
}

function Son() {
  Father.call(this);
}

let son1 = new Son();
let son2 = new Son();
console.log(son1.name);
console.log(son2.name);
console.log(son1.hobby);
console.log(son2.hobby);

son1.name = 'son';
son1.hobby.push('play games');
console.log('------------------');
console.log(son1);
console.log(son2);
console.log(son2.name);
console.log(son1.hobby);
console.log(son2.hobby);

打印結(jié)果:

這里并沒有采用原型鏈寻馏,而是利用call()方法,修改父構(gòu)造函數(shù)的指向核偿,來實現(xiàn)在子構(gòu)造函數(shù)中借用父構(gòu)造函數(shù)诚欠,完成繼承,這樣一來son1和son2都分別擁有自己的namehobby屬性,也就是打印結(jié)果的6,7行轰绵,son1和son2是完全獨立的家乘。這樣就解決了原型鏈繼承的第一個缺陷。我們再稍微修改一下Father構(gòu)造函數(shù):

function Father(name) {
  this.name = name;
  this.hobby = ['sport', 'read'];
}

function Son(name) {
  Father.call(this, name);
}

let son1 = new Son('Jack');
let son2 = new Son('Bob');
console.log(son1.name);
console.log(son2.name);
console.log(son1.hobby);
console.log(son2.hobby);

打印結(jié)果如下:

這樣就解決了原型鏈繼承的第二個傳參的問題藏澳,那我們?yōu)槭裁床徊捎媒栌脴?gòu)造函數(shù)繼承的方法呢仁锯?原因在于:這種繼承方法,所有的屬性和方法都需要在構(gòu)造函數(shù)中定義翔悠,比如我們需要綁定之前的sayF方法并繼承业崖,那么只能在Father的構(gòu)造函數(shù)里面寫,Father.prototype上的方法蓄愁,沒辦法通過這種方式繼承双炕,也就是說,如果把所有的屬性和方法都在構(gòu)造函數(shù)中定義的話撮抓,就不能對函數(shù)方法進行復用妇斤。 雖然我們依然可以通過實例對象來調(diào)用這個方法,但是卻是獨立存在于實例當中的丹拯,不屬于共享的方法站超。(你可以在Father構(gòu)造函數(shù)中添加一個方法,然后打印實例對象乖酬,可以看到實例對象中包含了這個方法死相,而這個方法不是存在于原型鏈上的)

組合繼承

我們了解了原型鏈繼承和借用構(gòu)造函數(shù)繼承后,我們可以發(fā)現(xiàn)這兩種繼承是互補的一個關(guān)系咬像。

  • 原型鏈繼承可以把方法定義在原型上算撮,從而復用方法。
  • 借用構(gòu)造函數(shù)繼承可以解決引用類型值的繼承問題和傳遞參數(shù)的問題县昂。
    因此肮柜,我們可以結(jié)合這兩種方法,就誕生了組合繼承倒彰,具體代碼實現(xiàn)如下:
function Father(name) {
  this.name = name;
  this.hobby = ['sport', 'read'];
}
Father.prototype.sayF = function () {
  console.log('father');
}

function Son(name, age) {
  Father.call(this, name);
  this.age = age;
}
Son.prototype = new Father();
Son.prototype.constructor = Son;
Son.prototype.sayS = function () {
  console.log('son');
}

let son1 = new Son('Jack', 20);
let son2 = new Son('Bob', 24);
console.log(son1);
console.log(son2);
son1.sayF();
son2.sayS();

打印結(jié)果如下:

我們在Father原型對象上定義了sayF()方法审洞,在Son原型對象上定義了sayS()方法,增加了Son.prototype = new Father();原型鏈狸驳。
最終實現(xiàn)了效果是预明,son1和son2都有各自的屬性缩赛,同時方法還綁定在兩個原型對象上耙箍,就達到了我們的目的:屬性獨立,方法復用
原型鏈負責原型對象上的方法酥馍,call借用構(gòu)造函數(shù)負責讓子類型擁有各自的屬性辩昆,組合繼承是js中最常用的繼承方式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旨袒,一起剝皮案震驚了整個濱河市汁针,隨后出現(xiàn)的幾起案子术辐,更是在濱河造成了極大的恐慌,老刑警劉巖施无,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辉词,死亡現(xiàn)場離奇詭異,居然都是意外死亡猾骡,警方通過查閱死者的電腦和手機瑞躺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兴想,“玉大人幢哨,你說我怎么就攤上這事∩┍悖” “怎么了捞镰?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毙替。 經(jīng)常有香客問我岸售,道長,這世上最難降的妖魔是什么厂画? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任冰评,我火速辦了婚禮,結(jié)果婚禮上木羹,老公的妹妹穿的比我還像新娘甲雅。我一直安慰自己,他們只是感情好坑填,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布抛人。 她就那樣靜靜地躺著,像睡著了一般脐瑰。 火紅的嫁衣襯著肌膚如雪妖枚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天苍在,我揣著相機與錄音绝页,去河邊找鬼。 笑死寂恬,一個胖子當著我的面吹牛续誉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播初肉,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酷鸦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起臼隔,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤嘹裂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摔握,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寄狼,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年氨淌,在試婚紗的時候發(fā)現(xiàn)自己被綠了例嘱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宁舰,死狀恐怖拼卵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛮艰,我是刑警寧澤腋腮,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站壤蚜,受9級特大地震影響即寡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜袜刷,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一聪富、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧著蟹,春花似錦墩蔓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涮雷,卻和暖如春阵面,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洪鸭。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工样刷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人览爵。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓置鼻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拾枣。 傳聞我的和親對象是個殘疾皇子沃疮,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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