面向?qū)ο?2 繼承

3.繼承

3.1 原型鏈

原型鏈?zhǔn)菍?shí)現(xiàn)繼承的主要方法姑曙。其基本思想是利用原型讓一個(gè)引用類(lèi)型繼承另一個(gè)引用類(lèi)型的屬性和方法。

構(gòu)造函數(shù)黍翎、原型和實(shí)例的關(guān)系

每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象贝淤,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針郭计。

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subproperty = false;
}
// 使SubType繼承SuperType的實(shí)例 本質(zhì)是重寫(xiě)原型對(duì)象
SubType.prototype = new SuperType();
SubType.prototype.getValue = function(){
    return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());//true

image

注意 :==instance.constructor現(xiàn)在指向的是SuperType,這是因?yàn)樵瓉?lái)SubType的原型指向了另一個(gè)對(duì)象--SuperType的原型霸琴,而這個(gè)原型對(duì)象的constructor屬性指向的是SuperType==

默認(rèn)的原型 Object
image
確定原型與實(shí)例的關(guān)系
  • instanceof:用這個(gè)操作符來(lái)測(cè)試實(shí)例與原型鏈中出現(xiàn)過(guò)的構(gòu)造函數(shù),結(jié)果就會(huì)返回true
alert(instance instanceof Object); //true
alert(instance instanceof SuperType); //true
alert(instance instanceof SubType); //true
  • 使用isPrototypeOf()方法昭伸,只要是原型鏈中出現(xiàn)的原型沈贝,都可以說(shuō)是該原型鏈所派生的實(shí)例的原型
alert(Object.prototype isPrototypeOf(instance)); //true
alert(SuperType.prototype isPrototypeOf(instance));
alert(SubType.prototype isPrototypeOf(instance));
通過(guò)原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法勋乾,因?yàn)檫@樣會(huì)重寫(xiě)原型鏈
function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subproperty = false;
}
SubType.prototype = new SuperType();
// 使用對(duì)象字面量創(chuàng)建原型方法宋下,會(huì)重寫(xiě)原型鏈
SubType.prototype = {
    getSubValue: function(){
        return this.subproperty;
    }
};
var instance = new SubType();
alert(instance.getSuperValue());//error!!
原型鏈的問(wèn)題
  • 包含引用類(lèi)型值的原型屬性會(huì)被所有實(shí)例共享,因此在構(gòu)造函數(shù)中定義屬性而不是在原型對(duì)象中定義屬性辑莫。
    在通過(guò)原型來(lái)實(shí)現(xiàn)繼承時(shí)学歧,原型實(shí)際上會(huì)變成另一個(gè)類(lèi)型的實(shí)例。于是各吨,原先的實(shí)例屬性也就變成了現(xiàn)在的原型屬性了枝笨。
function SuperType(){
    this.color = ["red", "blue", "green"];
    this.name = "Nicholas";
}
function SubType(){
}
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red","blue","green","black"
instance1.name = "Tom";
alert(instance1.name); //"Tom"

var instance2 = new SubType();
// colors是引用類(lèi)型,會(huì)被所有實(shí)例共享
alert(instance2.colors); // "red","blue","green","black"
alert(instance2.name); //"Nicholas"
  • 沒(méi)有辦法在不影響所有對(duì)象實(shí)例的情況下揭蜒,給超類(lèi)型的構(gòu)造函數(shù)傳遞參數(shù)
function SuperType(name){
    this.name = name;
}
function SubType(name){
}
// ??如何向超類(lèi)型的構(gòu)造函數(shù)傳遞參數(shù)横浑??
SubType.prototype = new SuperType();

var instance2 = new SubType(name);
  • 綜合以上情況屉更,實(shí)踐中很少會(huì)單獨(dú)使用原型鏈

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

在子類(lèi)型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類(lèi)型構(gòu)造函數(shù)徙融。

function SuperType(){
    this.colors=["red","blue","green"];
}
function SubType(){
    //
    superType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); // "red,blue,green,black"

bar instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"
使用這種方式,可以在子類(lèi)型構(gòu)造函數(shù)中向超類(lèi)型構(gòu)造函數(shù)傳遞參數(shù)瑰谜。
function SuperType(name){
    this.name=name;
}
function SubType(){
    Super.call(this,"Nicholas");
    this.age = 29;
}

var instance = new SubType();
alert(instance.name);//"Nicholas"
  • 相關(guān)問(wèn)題:

會(huì)出現(xiàn)與構(gòu)造函數(shù)模式相同的問(wèn)題——方法都在構(gòu)造函數(shù)中定義欺冀,函數(shù)復(fù)用就無(wú)從談起了。而且在超類(lèi)型的原型中定義的方法萨脑,對(duì)于子類(lèi)型也是不可見(jiàn)的隐轩。

3.3 組合繼承——JavaScrip最常用的繼承模式

使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承(通過(guò)在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用),通過(guò)借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承(保證每個(gè)實(shí)例都有自己的屬性渤早,而且可以向超類(lèi)的構(gòu)造函數(shù)傳遞參數(shù))职车。

function SuperType(name){
    this.name=name;
    this.colors=["red","blue","green"];
}

SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name,age){
    SuperType.call(this,name);
    this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas",29);
instance1.sayName(); //"Nicholas"
instance1.sayAge(); //29

var instance2 = new SubType("Greg",27);
instance2.sayName(); //"Greg"
instance2.sayAge(); //27

3.4 原型式繼承

借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類(lèi)型。

function object(o){
    // 臨時(shí)的構(gòu)造函數(shù)
    function F(){}
    // 將傳入的對(duì)象作為這個(gè)構(gòu)造函數(shù)的原型
    F.prototype = o;
    // 返回新實(shí)例
    return new F();
}
var person = {
    name:"Nicholas",
    friends:["shelby","court","van"]
};
// 以person為原型創(chuàng)建一個(gè)新實(shí)例
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "linda";
yetAnotherPerson.friends.push("barbie");

alert(person.friends); //"shelby,court,van,rob,barbie"

person.friends不僅屬于person所有悴灵,而且也會(huì)被anotherPerson军援、yetAnotherPerson共享。

ECMAScript5通過(guò)Object.create()方法規(guī)范化了原型式繼承称勋,這個(gè)方法接受兩個(gè)參數(shù):一個(gè)用作新對(duì)象原型的對(duì)象,另一個(gè)(可選的)為新對(duì)象定義額外屬性的對(duì)象涯竟。只傳入一個(gè)參數(shù)的情況赡鲜,和object()方法相同。

// Object.create()只用一個(gè)參數(shù)
var person = {
    name: "Nicholas",
    friends: ["shelby","court","van"]
};
var anotherPerson = Object.create(person);
// Object.create()用兩個(gè)參數(shù)
var person = {
    name: "Nicholas",
    friends: ["shelby","court","van"]
};
var anotherPerson = Object.create(person, {
    name:{
        value: "Greg"
    }
});
alert(anotherPerson.name); //Greg

var yetAnotherPerson = Object.create(person, {
    // 為新對(duì)象定義新的friends屬性庐船,該屬性會(huì)覆蓋原型屬性中的friends
    friends:{
        value: ["1","2","3"]
    }
});
alert(yetAnotherPerson.friends); //"1,2,3"
// 但是原型對(duì)象中的friends屬性仍然被共享
alert(person.friends); //"shelby,court,van"
alert(anothorPerson.friends); //"shelby,court,van"

3.5 寄生式繼承

function createAnother(original){
    var clone = object(original);
    // 不能做到函數(shù)復(fù)用银酬,導(dǎo)致效率降低
    // 添加新函數(shù),增強(qiáng)對(duì)象
    clone.sayHi = function(){
        alert("hi");
    }
    return clone;
}

var person = {
    name: "Nicholas",
    friends: ["shelby","court","van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

經(jīng)試驗(yàn)
使用原型式繼承方式出現(xiàn)如下問(wèn)題

function object(o){
    function F(){}
    F.sayHi = function(){
        alert("Hi");
    };
    F.prototype = o;
    return new F();
}
var person = {
    name:"Nicholas",
    friends:["shelby","court","van"]
};

var anotherPerson = object(person);
anotherPerson.sayHi(); 
會(huì)輸出錯(cuò)誤 VM6988:18 Uncaught TypeError: anotherPerson.sayHi is not a function

但是這種方式?jīng)]有問(wèn)題

function object(o){
    function F(){}
    F.prototype = o;
    // 返回新實(shí)例
    F.prototype.sayHi=function(){
        alert("Hi");
    }
    return new F();
}
var person = {
    name:"Nicholas",
    friends:["shelby","court","van"]
};
// 以person為原型創(chuàng)建一個(gè)新實(shí)例
var anotherPerson = object(person);
anotherPerson.sayHi(); //"Hi"
function object(o){
    function F(){
        this.sayHi = function(){
            alert("Hi");
        }
    }
    F.prototype = o;
    // 返回新實(shí)例
    
    return new F();
}
var person = {
    name:"Nicholas",
    friends:["shelby","court","van"]
};
// 以person為原型創(chuàng)建一個(gè)新實(shí)例
var anotherPerson = object(person);
anotherPerson.sayHi(); //"Hi"

原因分析

function F(){}
F.sayHi = function(){
        alert("Hi");
    };

2017.03.15 F.sayHi是定義了“類(lèi)”方法筐钟,因此創(chuàng)建的對(duì)象是沒(méi)有該方法的

3.6 寄生組合式繼承

組合繼承無(wú)論在什么情況下揩瞪,都會(huì)調(diào)用兩次超類(lèi)型構(gòu)造函數(shù):一次是在創(chuàng)建子類(lèi)型原型的時(shí)候,另一次是在子類(lèi)型構(gòu)造函數(shù)內(nèi)部篓冲。

function SuperType(name){
    this.name=name;
    this.colors=["red","blue","green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name,age){
    SuperType.call(this,name);   //第二次調(diào)用SuperType()
    this.age=age;
}
SubType.prototype = new SuperType(); //第一次調(diào)用SuperType()

第一次調(diào)用SuperType構(gòu)造函數(shù)時(shí)李破,SubType.prototype(SubType的原型)會(huì)得到兩個(gè)屬性:name和colors。當(dāng)調(diào)用SubType構(gòu)造函數(shù)時(shí)壹将,又會(huì)調(diào)用一次SuperType構(gòu)造函數(shù)嗤攻,這一次又在新對(duì)象上創(chuàng)建了實(shí)例屬性name和colors。于是這兩個(gè)屬性就屏蔽了原型中的兩個(gè)同名屬性

Markdown

為了避免創(chuàng)建兩次相同的屬性诽俯,解決方法——寄生組合式繼承妇菱。其基本思想是:不必為了指定子類(lèi)型的原型而調(diào)用超類(lèi)型的構(gòu)造函數(shù),我們所需要的無(wú)非就是超類(lèi)型原型的一個(gè)副本而已暴区。

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

function SuperType(name){
    this.name=name;
    this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName=function(){
    alert(this.name);
};
function SubType(name,age){
    SuperType.call(this,name);
    this.age=age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge=function(){
    alert(this.age);
};

上訴例子只調(diào)用了一次SuperType構(gòu)造函數(shù)闯团,因此避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性仙粱。寄生組合式繼承是引用類(lèi)型最理想的繼承范式
相比之下房交,第二段程序少了SubType.prototype = new SuperType();這使得SubType.prototype中沒(méi)有了name和colors屬性,實(shí)現(xiàn)了避免了在SubType.prototype上面創(chuàng)建不必要的伐割、多余的屬性的目的涌萤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市口猜,隨后出現(xiàn)的幾起案子负溪,更是在濱河造成了極大的恐慌,老刑警劉巖济炎,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件川抡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)崖堤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)侍咱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人密幔,你說(shuō)我怎么就攤上這事楔脯。” “怎么了胯甩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵昧廷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我偎箫,道長(zhǎng)木柬,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任淹办,我火速辦了婚禮眉枕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘怜森。我一直安慰自己速挑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布副硅。 她就那樣靜靜地躺著梗摇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪想许。 梳的紋絲不亂的頭發(fā)上伶授,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音流纹,去河邊找鬼糜烹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛漱凝,可吹牛的內(nèi)容都是我干的疮蹦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼茸炒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼愕乎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起壁公,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤感论,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后紊册,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體比肄,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芳绩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掀亥。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妥色,靈堂內(nèi)的尸體忽然破棺而出搪花,到底是詐尸還是另有隱情,我是刑警寧澤嘹害,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布撮竿,位于F島的核電站,受9級(jí)特大地震影響吼拥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜线衫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一凿可、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧授账,春花似錦枯跑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至屋确,卻和暖如春纳击,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背攻臀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工焕数, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刨啸。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓堡赔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親设联。 傳聞我的和親對(duì)象是個(gè)殘疾皇子善已,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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

  • 1.繼承(接口繼承和實(shí)現(xiàn)繼承) 繼承是 OO 語(yǔ)言中的一個(gè)最為人津津樂(lè)道的概念。許多 OO 語(yǔ)言都支持兩種繼承方式...
    believedream閱讀 952評(píng)論 0 3
  • 博客內(nèi)容:什么是面向?qū)ο鬄槭裁匆嫦驅(qū)ο竺嫦驅(qū)ο缶幊痰奶匦院驮瓌t理解對(duì)象屬性創(chuàng)建對(duì)象繼承 什么是面向?qū)ο?面向?qū)ο?..
    _Dot912閱讀 1,424評(píng)論 3 12
  • 本章內(nèi)容 理解對(duì)象屬性 理解并創(chuàng)建對(duì)象 理解繼承 面向?qū)ο笳Z(yǔ)言有一個(gè)標(biāo)志离例,那就是它們都有類(lèi)的概念换团,而通過(guò)類(lèi)可以創(chuàng)建...
    悶油瓶小張閱讀 852評(píng)論 0 1
  • 天真,天真宫蛆? 什么時(shí)候啥寇,大家對(duì)于天真是何其的贊賞,又如今,天真似乎開(kāi)始變成了“傻B”的代名詞 你有被別人評(píng)價(jià)過(guò)嗎辑甜?...
    心在baby路上閱讀 188評(píng)論 0 0
  • 在那遙遠(yuǎn)的地方 有位美麗的女郎 哦衰絮,我心愛(ài)的姑娘 我夢(mèng)見(jiàn)你的臉龐 瞧瞧你的衣裳 你不是我的新娘 我不是你的情郎 不...
    狼吻與蝶花閱讀 127評(píng)論 0 1