【二十八】原型繼承

在傳統(tǒng)的基于Class的語言如Java殉摔、C++中焰雕,繼承的本質(zhì)是擴(kuò)展一個(gè)已有的Class,并生成新的Subclass浊仆。
由于這類語言嚴(yán)格區(qū)分類和實(shí)例客峭,承實(shí)際上是類型的擴(kuò)展。但是抡柿,JavaScript由于采用原型繼承舔琅,我們無法直接擴(kuò)展一個(gè)Class,因?yàn)楦静淮嬖贑lass這種類型洲劣。
但是辦法還是有的备蚓。我們先回顧Student構(gòu)造函數(shù):

function Student(props) {
    this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function() {
    alert('Hello, ' + this.name + '!');
}

以及Student的原型鏈:

現(xiàn)在课蔬,我們要基于Student擴(kuò)展出PrimaryStudent,可以先定義出PrimaryStudent:

function PrimaryStudent(props) {
    // 調(diào)用Student構(gòu)造函數(shù)郊尝,綁定this變量:
    Student.call(this, props);
    this.grade = props.grade || 1;
}

但是二跋,調(diào)用了Student構(gòu)造函數(shù)不等于繼承了Student,PrimaryStudent創(chuàng)建的對象的原型是:

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Object.prototype ----> null

必須想辦法把原型鏈修改為:

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Student.prototype ----> Object.prototype ----> null

這樣流昏,原型鏈對了扎即,繼承關(guān)系就對了。新的基于PrimaryStudent創(chuàng)建的對象不但能調(diào)用PrimaryStudent.prototype定義的方法况凉,也可以調(diào)用Student.prototype定義的方法谚鄙。
如果你想用最簡單粗暴的方法這么干:

PrimaryStudent.prototype = Student.prototype;

是不行的!如果這樣的話刁绒,PrimaryStudent和Student共享一個(gè)原型對象闷营,那還要定義PrimaryStudent干啥?
我們必須借助一個(gè)中間對象來實(shí)現(xiàn)正確的原型鏈知市,這個(gè)中間對象的原型要指向Student.prototype傻盟。
為了實(shí)現(xiàn)這一點(diǎn),參考道爺(就是發(fā)明JSON的那個(gè)道格拉斯)的代碼嫂丙,中間對象可以用一個(gè)空函數(shù)F來實(shí)現(xiàn):

// PrimaryStudent構(gòu)造函數(shù):
function PrimaryStudent(props) {
    Student.call(this, props);
    this.grade = props.grade || 1;
}

// 空函數(shù)F:
function F() {
}

//把F的原型指向Student.prototype:
F.prototype = Student.prototype;

// 把PrimaryStudent的原型指向一個(gè)新的F對象莫杈,F(xiàn)對象的原型正好指向Student.prototype:
PrimaryStudent.prototype = new F();

// 把PrimaryStudent原型的構(gòu)造函數(shù)修復(fù)為PrimaryStudent:
PrimaryStudent.prototype.constructor = PrimaryStudent;

// 繼續(xù)在PrimaryStudent原型(就是new F()對象)上定義方法:
PrimaryStudent.prototype.getGrade = function () {
    return this.grade;
};

// 創(chuàng)建xiaoming:
var xiaoming = new PrimaryStudent({
    name: '小明',
    grade: 2
});
xiaoming.name;  // '小明'
xiaoming.grade;  // 2

//  驗(yàn)證原型:
xiaoming.__proto__ === PrimaryStudent.prototype;  // true
xiaoming.__proto__.__proto__ === Student.prototype;  // true

// 驗(yàn)證繼承關(guān)系:
xiaoming instanceof PrimaryStudent;  // true
xiaoming instanceof Student;  // true

用一張圖來表示新的原型鏈:

<u>注意,函數(shù)F僅用于橋接奢入,我們僅創(chuàng)建了一個(gè)new F()實(shí)例筝闹,而且,沒有改變原有的Student定義的原型鏈腥光。</u>
如果把繼承這個(gè)動作用一個(gè)inherits()函數(shù)封裝起來关顷,還可以隱藏F的定義,并簡化代碼:

function inherits(Child, Parent) {
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child; 
}

這個(gè)inherits()函數(shù)可以復(fù)用:

function Student(props) {
    this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

function PrimaryStudent(props) {
    Student.call(this.props);
    this.grade = props.grade || 1;
}

//  實(shí)現(xiàn)原型繼承鏈:
inherits(PrimaryStudent, Student);

//  綁定其他方法到PrimaryStudent原型:
PrimaryStudent.prototype.getGrade = function () {
    return this.grade;
};

</br>

小結(jié)

JavaScript的原型繼承實(shí)現(xiàn)方式就是:

  1. 定義新的構(gòu)造函數(shù)武福,并在內(nèi)部用call()調(diào)用希望“繼承”的構(gòu)造函數(shù)议双,并綁定this;
  2. 借助中間函數(shù)F實(shí)現(xiàn)原型鏈繼承,最好通過封裝的inherits函數(shù)完成捉片;
  3. 繼續(xù)在新的構(gòu)造函數(shù)的原型上定義新方法平痰。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伍纫,隨后出現(xiàn)的幾起案子宗雇,更是在濱河造成了極大的恐慌,老刑警劉巖莹规,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赔蒲,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舞虱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門欢际,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人矾兜,你說我怎么就攤上這事损趋。” “怎么了椅寺?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵浑槽,是天一觀的道長。 經(jīng)常有香客問我配并,道長括荡,這世上最難降的妖魔是什么高镐? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任溉旋,我火速辦了婚禮,結(jié)果婚禮上嫉髓,老公的妹妹穿的比我還像新娘观腊。我一直安慰自己,他們只是感情好算行,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布梧油。 她就那樣靜靜地躺著,像睡著了一般州邢。 火紅的嫁衣襯著肌膚如雪儡陨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天量淌,我揣著相機(jī)與錄音骗村,去河邊找鬼。 笑死呀枢,一個(gè)胖子當(dāng)著我的面吹牛胚股,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播裙秋,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼琅拌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摘刑?” 一聲冷哼從身側(cè)響起进宝,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枷恕,沒想到半個(gè)月后即彪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年隶校,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漏益。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡深胳,死狀恐怖绰疤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舞终,我是刑警寧澤轻庆,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站敛劝,受9級特大地震影響余爆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夸盟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一蛾方、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧上陕,春花似錦桩砰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至庶溶,卻和暖如春煮纵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背偏螺。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工行疏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砖茸。 一個(gè)月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓隘擎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凉夯。 傳聞我的和親對象是個(gè)殘疾皇子货葬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

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