js 繼承

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

  類式繼承是在函數(shù)對(duì)象內(nèi)調(diào)用父類的構(gòu)造函數(shù),使得自身獲得父類的方法和屬性。call和apply方法為類式繼承提供了支持。通過改變this的作用環(huán)境,使得子類本身具有父類的各種屬性。

只繼承構(gòu)造函數(shù)的屬性,不繼承原型的屬性。 解決原型鏈缺點(diǎn)??梢岳^承多個(gè)構(gòu)造函數(shù)的屬性,在子實(shí)例中可以向父類傳參。

缺點(diǎn):無法實(shí)現(xiàn)構(gòu)造函數(shù)的復(fù)用;每個(gè)新實(shí)例都有父類構(gòu)造函數(shù)副本,臃腫。

var?father =?function() {

??this.age = 52;

??this.say =?function() {

????alert('hello i am '+?this.name?' and i am '+this.age +?'years old');

??}

}

var?child =?function() {

??this.name =?'bill';

??father.call(this);

}

var?man =?new?child();

man.say();

原型鏈繼承(借用原型鏈實(shí)現(xiàn)繼承)

function Parent1(){ this.name = "parent1"; this.colors = ["red","blue","yellow"]; } function Child1(){ this.name = "child1"; } Child1.prototype = new Parent1();//把子類的prototype設(shè)置為父類的實(shí)例

實(shí)例可繼承的屬性有:實(shí)例構(gòu)造函數(shù)的屬性,父類構(gòu)造函數(shù)屬性,父類原型的屬性,新實(shí)例不會(huì)繼承父類實(shí)例的屬性。

優(yōu)點(diǎn):繼承了父類的模板,又繼承了父類的原型對(duì)象,

缺點(diǎn):1 如果屬性是引用類型的話,會(huì)共享引用類型。

2 新實(shí)例無法向父類構(gòu)造函數(shù)傳參,繼承單一。父類實(shí)例傳參,不是子類實(shí)例化傳參。


組合式繼承

1 可以繼承父類原型上的屬性,可以傳參,可以服用。

2 每個(gè)新實(shí)例引入構(gòu)造函數(shù)屬性上私有的。

缺點(diǎn):調(diào)用兩次父類構(gòu)造函數(shù),耗內(nèi)存。子類的構(gòu)造函數(shù)會(huì)代替原型上的構(gòu)造函數(shù)。

這里所謂的組合是指組合借用構(gòu)造函數(shù)和原型鏈繼承兩種方式。

function Parent2(){ this.name = "parent2"; this.colors = ["red","blue","yellow"]; } function Child2(){ Parent2.call(this); this.type = "child2"; } Child2.prototype = new Parent2()

注意第6,9行,這種方式結(jié)合了借用構(gòu)造函數(shù)繼承和原型鏈繼承的有點(diǎn),能否解決上述兩個(gè)實(shí)例對(duì)象沒有被隔離的問題呢?

var s1 = new Child2(); s1.colors.push("black"); var s2 = new Child2(); s1.colors; // (4) ["red", "blue", "yellow", "balck"] s2.colors; // (3) ["red", "blue", "yellow"]

可以看到,s2和s1兩個(gè)實(shí)例對(duì)象已經(jīng)被隔離了。

但這種方式仍有缺點(diǎn)。父類的構(gòu)造函數(shù)被執(zhí)行了兩次,第一次是Child2.prototype = new Parent2(),第二次是在實(shí)例化的時(shí)候,這是沒有必要的。

組合式繼承優(yōu)化1

直接把父類的原型對(duì)象賦給子類的原型對(duì)象

function Parent3(){ this.name = "parent3"; this.colors = ["red","blue","yellow"]; } Parent3.prototype.sex = "男"; Parent3.prototype.say = function(){console.log("Oh, My God!")} function Child3(){ Parent3.call(this); this.type = "child3"; } Child3.prototype = Parent3.prototype; var s1 = new Child3(); var s2 = new Child3(); console.log(s1, s2);

但是,我們來看如下代碼:

console.log(s1 instanceof Child3); // true console.log(s1 instanceof Parent3); // true

可以看到,我們無法區(qū)分實(shí)例對(duì)象s1到底是由Child3直接實(shí)例化的還是Parent3直接實(shí)例化的。用instanceof關(guān)鍵字來判斷是否是某個(gè)對(duì)象的實(shí)例就基本無效了。

我們還可以用.constructor來觀察對(duì)象是不是某個(gè)類的實(shí)例:

console.log(s1.constructor.name); // Parent3

從這里可以看到,s1的構(gòu)造函數(shù)居然是父類,而不是子類Child3,這顯然不是我們想要的。

組合式繼承優(yōu)化2

這是繼承的最完美方式

function Parent4(){ this.name = "parent4"; this.colors = ["red","blue","yellow"]; } Parent4.prototype.sex = "男"; Parent4.prototype.say = function(){console.log("Oh, My God!")} function Child4(){ Parent4.call(this); this.type = "child4"; } Child4.prototype = Object.create(Parent4.prototype); Child4.prototype.constructor = Child4;

Object.create是一種創(chuàng)建對(duì)象的方式,它會(huì)創(chuàng)建一個(gè)中間對(duì)象

var p = {name: "p"} var obj = Object.create(p) // Object.create({ name: "p" })

通過這種方式創(chuàng)建對(duì)象,新創(chuàng)建的對(duì)象obj的原型就是p,同時(shí)obj也擁有了屬性name,這個(gè)新創(chuàng)建的中間對(duì)象的原型對(duì)象就是它的參數(shù)。

這種方式解決了上面的所有問題,是繼承的最完美實(shí)現(xiàn)方式。

ES6中繼承

Class?可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這比 ES5 的通過修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多。

class Parent { } class Child1 extends Parent { constructor(x, y, colors) { super(x, y); // 調(diào)用父類的constructor(x, y) this.colors = colors; } toString() { return this.colors + ' ' + super.toString(); // 調(diào)用父類的toString() } }

上面代碼中,constructor方法和toString方法之中,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù),用來新建父類的this對(duì)象。

子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)。如果子類沒有定義constructor方法,這個(gè)方法會(huì)被默認(rèn)添加,不管有沒有顯式定義,任何一個(gè)子類都有constructor方法。

ES5 的繼承,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對(duì)象this,然后再將父類的方法添加到this上面(Parent.apply(this))。

ES6 的繼承機(jī)制完全不同,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對(duì)象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 借用構(gòu)造函數(shù)繼承 原型鏈?zhǔn)嚼^承(借用原型鏈實(shí)現(xiàn)繼承) 組合式繼承 組合式繼承優(yōu)化1 組合式繼承優(yōu)化2 ES6中繼承...
    lxt410725閱讀 373評(píng)論 0 1
  • 繼承的概念:子類可以使用父類共享的屬性和方法,避免重復(fù)代碼提高代碼復(fù)用性。 原型鏈:子類可以共享父類的實(shí)例對(duì)象和實(shí)...
    淺秋_6672閱讀 462評(píng)論 0 0
  • 一、原型鏈 學(xué)過java的同學(xué)應(yīng)該都知道,繼承是java的重要特點(diǎn)之一,許多面向?qū)ο蟮恼Z言都支持兩種繼承方式:接口...
    grain先森閱讀 1,482評(píng)論 0 39
  • 一.構(gòu)造繼承 構(gòu)造函數(shù)繼承: function Super(){ this.colors= ['c','a','b...
    yuanjiex閱讀 256評(píng)論 0 1
  • 萬籟俱寂的夜里 突然傳來雨的聲音 非常雜亂的聲音 讓我瞬間驚醒 翻身起來關(guān)窗 再次躺下后 卻輾轉(zhuǎn)反側(cè)難以入睡 雨落...
    古商城饞師閱讀 203評(píng)論 0 0

友情鏈接更多精彩內(nèi)容