js中的實現(xiàn)繼承的幾種方式

大綱:
  • 原型鏈
  • 借用構(gòu)造函數(shù)
  • 組合繼承
  • 原型式繼承
  • 寄生式繼承
  • 寄生組合式繼承

1、原型鏈:

  • 什么是原型鏈烁设?

原型鏈的基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法

 function Father(){     
    this.hair = "black";
  }
  Father.prototype.getHair = function(){
    return this.hair
  }

  function Son(){
    this.eyes = "blue";
  }
//Son繼承了Father
//沒有使用Son的默認原型檬某,而是換了一個新原型撬腾。本質(zhì)是重寫原型
  Son.prototype = new Father();
 
  Son.prototype.getEyes =  function(){
    return this.eyes;
  }
//Son的實例對象,并不是函數(shù)
  var Gson = new Son();
  console.log(Gson.getHair());           //black
  console.log(Gson.getEyes());         //blue
  console.log(Son.prototype.getHair());       //black
  • 繼承的實現(xiàn):

1恢恼、通過創(chuàng)建Father的實例賦值給Son.prototype實現(xiàn)的繼承民傻。
2、實現(xiàn)的本質(zhì)是重寫原型對象场斑,以一個新類型的實例取代漓踢。
3、即存在Father實例中的所有屬性和方法漏隐,現(xiàn)在也存在Son.prototype中了

  • 捋一下Object喧半,F(xiàn)ather和Son,Gson之間的關(guān)系:

1青责、所有的引用類型都默認繼承了Object挺据,繼承的方式也是原型鏈
2、Gson是Son的實例對象脖隶,通過var Gson = new Son()扁耐。此時Gson里的__ proto__指向Son的prototype。

  console.log(Gson.__proto__ == Son.prototype);   //true

3产阱、Son繼承了Father婉称,通過Son.prototype = new Father()。此時Son的prototype作為實例對象,他的__ proto__屬性指向Father的prototype

console.log(Son.prototype.__proto__ == Father.prototype);  //true

4王暗、由于Son實現(xiàn)繼承的本質(zhì)是重寫原型對象悔据。Son.prototye的constructor屬性已經(jīng)不再指向Son。而是指向Father

console.log(Son.prototype.constructor == Son);   //false
console.log(Son.prototype.constructor == Father);    //true

5俗壹、所有函數(shù)的默認原型都是Object的實例科汗,所以默認的原型都有__ proto__屬性指向Object.prototye。這也是所有自定義類型都會繼承toString(),valueOf()等默認方法的根本原因

console.log(Father.prototype.__proto__ == Object.prototype);  //true
console.log(Son.prototype.__proto__ == Object.prototype);  //true

6策肝、Son繼承了Father肛捍,F(xiàn)ather繼承了Object。而Gson是Son的實例對象之众。

  • 簡單圖示:


    image.png
  • 注意:

不能使用對象字面量創(chuàng)建原型方法拙毫。因為會改變constructor的指向,會導(dǎo)致原型鏈被切斷

  • 問題:

1棺禾、包含引用類型值的原型缀蹄。
2、在創(chuàng)建子類型的實例時膘婶,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)

 function Father(){
    this.colors = ["black","blue","red"]
  }
  function Son(){}

  Son.prototype = new Father();

  var Gson1 = new Son();
  Gson1.colors.push("yellow");
  console.log(Gson1.colors);   //["black", "blue", "red", "yellow"]

  var Gson2 = new Son();  
  console.log(Gson2.colors);    //["black", "blue", "red", "yellow"]
//這是因為Father的實例對象是Son.prototye缺前,而prototype屬性上的方法和屬性都會共享

2、借用構(gòu)造函數(shù):(偽造對象或經(jīng)典繼承)

  • 基本思想:

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

  • 例子:

實際上是在Son的要創(chuàng)建的新實例(Gson1,Gson2)環(huán)境下調(diào)用了Father衅码。
1、使用Father.call()方法脊岳,可以解決原型鏈包含引用類型值的原型的問題

 function Father(){
    this.colors = ["black","blue","red"]
  }
  function Son(){
    Father.call(this)        //this指向Son的新實例對象
  }

  var Gson1 = new Son();
  Gson1.colors.push("yellow");
  console.log(Gson1.colors);   //["black", "blue", "red", "yellow"]

  var Gson2 = new Son();  
  console.log(Gson2.colors);    //["black", "blue", "red"]

2逝段、解決原型鏈傳遞參數(shù)問題

function Father(name){
    this.name = name
  }
  function Son(){
    //繼承了Father,并傳遞參數(shù)
    Father.call(this,"Tom");
    //實例屬性,要在繼承之后添加
    this.age = 36;      
  }

  var Gson = new Son();
  console.log(Gson.name);     //Tom
  console.log(Gson.age);      //36 

3割捅、組合繼承:(偽經(jīng)典繼承)

是將原型鏈和借用構(gòu)造函數(shù)相結(jié)合奶躯。
1、使用原型鏈實現(xiàn)對原型屬性和方法的繼承
2亿驾、通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承

  • 優(yōu)點:

1嘹黔、通過在原型上定義方法實現(xiàn)了函數(shù)復(fù)用
2、還能保證每個實例都有它自己的屬性

  • 例子:
 function Father(){
    this.colors= ["black","blue","red"];   
  }
 
  function Son(name,age){
    //繼承屬性
    Father.call(this);
    this.name = name;
    this.age = age; 
  }

  //繼承方法
  Son.prototype = new Father();
  Son.prototype.constructor = Son;
  Son.prototype.isAge = function(){
    console.log(this.age);
}
  Son.prototype.isName = function(){
    console.log(this.name);
  }


  var Gson1 = new Son("lili",11);
  Gson1.colors.push("yellow")
  console.log(Gson1.colors);         //["black", "blue", "red", "yellow"]
  console.log(Gson1.name);         //lili
  console.log(Gson1.age);            //11

  var Gson2 = new Son("bree",20);
  console.log(Gson2.colors);       //["black", "blue", "red"]
  console.log(Gson2.name);        //bree
  console.log(Gson2.age);          //20
  • 問題:

1莫瞬、無論什么情況下儡蔓,都會調(diào)用兩次超類型構(gòu)造函數(shù)。
2疼邀、一次是在創(chuàng)建子類型原型的適合
3喂江、另一次是在子類型構(gòu)造函數(shù)內(nèi)部

4、原型式繼承

  • 思想:

借助原型可以基于已有的對象創(chuàng)建新對象檩小,同時不必因此創(chuàng)建自定義類型开呐。

function obj(o){ //本質(zhì)上obj()對傳入的對象執(zhí)行了一次淺復(fù)制
        function F(){}
        F.prototype = o;
        return new F();
    }
var lion = {
        name:"lion",
        friends:["giraffe","elephant","rabbit"]
    }
//將lion傳入obj中烟勋,返回一個新對象规求。
//這個新對象的原型指向lion
//即lion上的屬性被加到新對象上的原型上了
    var fox = obj(lion);
    fox.name = "fox";
    fox.friends.push("cat");     //friends屬性被共享了

    var wolf = obj(lion);
    wolf.name = "wolf";
    wolf.friends.push("tiger");

console.log(lion.friends); //["giraffe", "elephant", "rabbit", "cat", "tiger"]
  • Object.create方法:

1筐付、只有一個參數(shù)時,用法和obj()一樣
2阻肿、有兩個參數(shù)時瓦戚,用法如下:

var lion = {
        name:"lion",
        friends:["giraffe","elephant","rabbit"]
    }
//類似描述符修改屬性
    var fox = Object.create(lion,{
        name:{
            value:"fox"
        }
    });
    console.log(fox.name);
  • 優(yōu)點:

當(dāng)沒有必要創(chuàng)建構(gòu)造函數(shù),只想讓一個對象與另一個對象保持類似的情況下丛塌,原型式繼承是完全可以勝任的较解。

  • 缺點:

包含引用類型值的屬性始終會共享相應(yīng)的值。

5赴邻、寄生式繼承:

  • 本質(zhì):

1印衔、創(chuàng)建一個僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強對象姥敛,最后再想真的是他做了所有工作一樣返回對象
2奸焙、與寄生構(gòu)造函數(shù)和工廠模式類似

function obj(o){ 
        function F(){}
        F.prototype = o;
        return new F();
    }
    function clo(z){       //封裝繼承過程
        var clone = obj(z);      //繼承函數(shù)
        clone.sayHi = function(){
            alert('hi') 
        };
        return clone            //返回
    }
    var lion = {
        name:"lion",
        friends:["giraffe","elephant","rabbit"]
    }
    var zoo = clo(lion);
    zoo.sayHi()        //hi
    console.log(zoo.name); //lion
    console.log(zoo.friends); //["giraffe", "elephant", "rabbit"]
  • 注意:

obj()不是必需的,任何能夠返回新對象的函數(shù)都適用于此模式

  • 缺點:

使用寄生式繼承來為對象添加函數(shù)彤敛,會由于不能做到函數(shù)復(fù)用而降低效率与帆,與構(gòu)造函數(shù)模式類似。

6墨榄、寄生組合式繼承

  • 概念:

通過借用構(gòu)造函數(shù)來繼承屬性玄糟,通過原型鏈的混成形式來繼承方法

  • 基本思路:

不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無非就是超類型原型的一個副本而已

  • 本質(zhì):

使用寄生式繼承來繼承超類型的原型袄秩,然后再將結(jié)果指定給子類型的原型阵翎。

  • 例子:
function obj(o){ 
        function F(){}
        F.prototype = o;
        return new F();
    }
    function inher(son,father){
        var pro = obj(father.prototype);  //創(chuàng)建對象
        pro.constructor = son;     //增強對象
        son.prototype = pro;    //指定對象
    }
    function Father(name){
        this.name = name;
        this.colors = ["black","blue","yellow"]
    }
    Father.prototype.isName = function(){
        alert(this.name)
    }
    function Son(name,age){
        Father.call(this,name);    //只調(diào)用一次Father
        this.age=age;
    }
    inher(Son,Father);
    Son.prototype.isAge=function(){
        alert(this.age)
    }
  • 優(yōu)點:

1、只調(diào)用一次Father構(gòu)造函數(shù)播揪,也避免了再Son.prototype上面創(chuàng)建不必要的屬性贮喧。
2、原型鏈能保持不變
3猪狈、是引用類型最理想的繼承方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末箱沦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雇庙,更是在濱河造成了極大的恐慌谓形,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疆前,死亡現(xiàn)場離奇詭異寒跳,居然都是意外死亡,警方通過查閱死者的電腦和手機竹椒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門童太,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事书释∏讨” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵爆惧,是天一觀的道長狸页。 經(jīng)常有香客問我,道長扯再,這世上最難降的妖魔是什么芍耘? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮熄阻,結(jié)果婚禮上斋竞,老公的妹妹穿的比我還像新娘。我一直安慰自己秃殉,他們只是感情好窃页,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著复濒,像睡著了一般脖卖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巧颈,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天畦木,我揣著相機與錄音,去河邊找鬼砸泛。 笑死十籍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唇礁。 我是一名探鬼主播勾栗,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盏筐!你這毒婦竟也來了围俘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤琢融,失蹤者是張志新(化名)和其女友劉穎界牡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漾抬,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡宿亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纳令。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挽荠。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡克胳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出圈匆,到底是詐尸還是另有隱情毯欣,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布臭脓,位于F島的核電站,受9級特大地震影響腹忽,放射性物質(zhì)發(fā)生泄漏来累。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一窘奏、第九天 我趴在偏房一處隱蔽的房頂上張望嘹锁。 院中可真熱鬧,春花似錦着裹、人聲如沸领猾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摔竿。三九已至,卻和暖如春少孝,著一層夾襖步出監(jiān)牢的瞬間继低,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工稍走, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留袁翁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓婿脸,卻偏偏與公主長得像粱胜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狐树,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354