Javascript面向?qū)ο? 繼承的幾種方式

原型鏈

ECMAScript中將原型鏈作為實現(xiàn)繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法兄一。

  • 基本模式
function SuperType() {
    this.property = true;
    this.colors = ["a", "b"];
}

SuperType.prototype.getSuperValue = function(){
    console.log(this.property);
};

function SubType() {
    this.subProperty = false;
}

SubType.prototype = new SuperType();
// SubType.prototype = Object.create(SuperType.prototype);

SubType.prototype.getSubValue = function(){
    console.log(this.subProperty);
};

var instance = new SubType();
instance.getSuperValue();

結(jié)果:


B2141495-7F1C-459E-AD14-7FCD44D622C3.png

上面的例子中,instance指向SubType的原型费薄,SubType的原型又指向SuperType的原型楞抡。getSuperValue()方法仍然還在SuperType.prototype中析藕,但property則位于SubType.prototype中账胧。這是因為prototype是一個實例屬性治泥,而getSuperValue()則是一個原型方法居夹。

注意:原型鏈雖然很強大,可以實現(xiàn)繼承檬洞,但存在兩個主要的問題添怔。
(1)包含引用類型值的原型屬性會被所有實例共享广料,這會導(dǎo)致對一個實例的修改會影響另一個實例性昭。
(2)在創(chuàng)建子類型的實例時糜颠,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)其兴。由于這兩個問題的存在元旬,實踐中很少單獨使用原型鏈守问。

function SuperType() {
        this.property = true;
        this.colors = ["a", "b"];
}

SuperType.prototype.getSuperValue = function(){
        console.log(this.property);
};

function SubType() {
        this.subProperty = false;
}

SubType.prototype = new SuperType();
// SubType.prototype = Object.create(SuperType.prototype);

SubType.prototype.getSubValue = function(){
        console.log(this.subProperty);
};

var instance1 = new SubType();
instance1.colors.push("c");

console.log(instance1.colors);

var instance2 = new SubType();
console.log(instance2.colors);

結(jié)果:


CC1EB7F7-4033-4DA9-9599-20DCE1A97259.png

會發(fā)現(xiàn)引用類型值的原型屬性會被所有實例共享穆端。

  • 借用構(gòu)造函數(shù)
    在解決原型中包含引用類型值所帶來的問題中体啰,使用借用構(gòu)造函數(shù)技術(shù)來解決荒勇。借用構(gòu)造函數(shù)的基本思想沽翔,即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)仅偎。函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對象哨颂,因此通過使用apply()和call()方法可以在新創(chuàng)建的對象上執(zhí)行構(gòu)造函數(shù)威恼。如下例子
function SuperType() {
        this.colors = ["a", "b"];
}

function SubType() {
        SuperType.call(this);
        this.subProperty = false;
}

var instance1 = new SubType();
instance1.colors.push("c");
console.log(instance1.colors);

var instance2 = new SubType();
console.log(instance2.colors);

結(jié)果:


BE163E43-7D13-4F68-8F95-31F7D7D81B56.png

上面例子中,通過使用call()方法(或者apply()方法)斤蔓,在新創(chuàng)建的SubType實例的環(huán)境下調(diào)用了SuperType構(gòu)造函數(shù)弦牡。這樣一來就會在新的SubType對象上執(zhí)行SuperType()函數(shù)中定義的所有對象初始化代碼。結(jié)果椭豫,SubType的每個實例都會有自己的colors屬性副本赏酥。

相對于原型鏈而言裸扶,借用構(gòu)造函數(shù)可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)姓言。如下例子

function SuperType(name) {
        this.name = name;
}

function SubType() {
        SuperType.call(this, "Lee");
        this.age = 28;
}

var instance1 = new SubType();
console.log(instance1.name);
console.log(instance1.age);

結(jié)果:


A9B61920-3DF3-4F8F-B8EA-D6EB0D4A097C.png

借用構(gòu)造函數(shù)存在兩個問題:
(1)無法避免構(gòu)造函數(shù)模式存在的問題,方法都在構(gòu)造函數(shù)中定義餐塘,因此無法復(fù)用函數(shù)税手。
(2)在超類型的原型中定義的方法芦倒,對子類型而言是不可見的兵扬。因此這種技術(shù)很少單獨使用器钟。

  • 組合繼承

組合繼承,指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一起昙啄。思路是使用原型鏈實現(xiàn)對原型方法的繼承跟衅,而通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。這樣叭莫,既通過在原型上定義方法實現(xiàn)了函數(shù)的復(fù)用,又能夠保證每個實例都有它自己的屬性靖诗。以下例子充分說明了這一點

function SuperType(name) {
    this.name = name;
    this.colors = ["a", "b"];
}

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

function SubType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    console.log(this.age);
};

var instance1 = new SubType("Lee", 28);
instance1.colors.push("c");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("Hui", 27);
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

結(jié)果:


3C91027C-32B2-4C26-ADA3-5F6764A929D9.png

這個例子中颂鸿,兩個實例既分別擁有自己的屬性,包括colors屬性,又可以使用相同的方法稳懒。

組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺點僚祷,融合了他們的優(yōu)點俺榆,是JavaScript中最常用的繼承模式定嗓。
缺點:實際上子類上會擁有超類的兩份屬性,只是子類的屬性覆蓋了超類的屬性

  • 原型式繼承
    采用原型式繼承并不需要定義一個類恃逻,傳入?yún)?shù)obj,生成一個繼承obj對象的對象
function objectCreate(obj){
  function F(){}
  F.prototype = obj
  return new F()
}

直接通過對象生成一個繼承該對象的對象,但是不是類式繼承,而是原型式基礎(chǔ),缺少了類的概念找田。

  • 寄生式繼承
    創(chuàng)建一個僅僅用于封裝繼承過程的函數(shù),然后在內(nèi)部以某種方式增強對象植袍,最后返回對象
function objectCreate(obj){
  function F(){}
  F.prototype = obj
  return new F()
}
function createSubObj(superInstance){
  var clone = objectCreate(superInstance)
  clone.property = 'Sub Property'
  return clone
}

原型式繼承的一種拓展,但是依舊沒有類的概念。

  • 寄生組合式繼承
    結(jié)合寄生式繼承和組合式繼承,完美實現(xiàn)不帶兩份超類屬性的繼承方式
function inheritPrototype(Super,Sub){
  var superProtoClone = Object.Create(Super.prototype)
  superProtoClone.constructor = Sub
  Sub.prototype = Super
}
function Sub(){
  Super.call()
  Sub.property = 'Sub Property'
}
inheritPrototype(Super,Sub)

完美實現(xiàn)繼承,解決了組合式繼承帶兩份屬性的問題腕窥,過于繁瑣癞松,故不如組合繼承。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末入蛆,一起剝皮案震驚了整個濱河市拦惋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌安寺,老刑警劉巖厕妖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挑庶,居然都是意外死亡言秸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門迎捺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來举畸,“玉大人,你說我怎么就攤上這事凳枝〕冢” “怎么了跋核?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叛买。 經(jīng)常有香客問我砂代,道長,這世上最難降的妖魔是什么率挣? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任刻伊,我火速辦了婚禮,結(jié)果婚禮上椒功,老公的妹妹穿的比我還像新娘捶箱。我一直安慰自己,他們只是感情好动漾,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布丁屎。 她就那樣靜靜地躺著,像睡著了一般旱眯。 火紅的嫁衣襯著肌膚如雪晨川。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天键思,我揣著相機與錄音,去河邊找鬼甫贯。 笑死吼鳞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叫搁。 我是一名探鬼主播赔桌,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渴逻!你這毒婦竟也來了疾党?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惨奕,失蹤者是張志新(化名)和其女友劉穎雪位,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梨撞,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡雹洗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了卧波。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片时肿。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖港粱,靈堂內(nèi)的尸體忽然破棺而出螃成,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布寸宏,位于F島的核電站宁炫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏击吱。R本人自食惡果不足惜淋淀,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望覆醇。 院中可真熱鬧朵纷,春花似錦、人聲如沸永脓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽常摧。三九已至搅吁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間落午,已是汗流浹背谎懦。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留溃斋,地道東北人界拦。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像梗劫,于是被迫代替她去往敵國和親享甸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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