繼承的幾種方式

構(gòu)造函數(shù),原型和實(shí)例的關(guān)系
每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象prototype,原型對(duì)象中有個(gè)constructor屬性,該屬性指向構(gòu)造函數(shù)本身,每個(gè)實(shí)例都有一個(gè)指向原型對(duì)象的內(nèi)部指針proto,如果原型對(duì)象是另一個(gè)實(shí)例,那原型對(duì)象中又包含一個(gè)指向其原型的指針
所有引用類型都是繼承了object
所有函數(shù)的默認(rèn)原型都是Object的實(shí)例
默認(rèn)原型中包含一個(gè)指針指向object.prototype

image.png

image.png

1、原型鏈

  function Animal() {
       this.color=['red','blue']
   }
   Animal.prototype.eat=function(){
       console.log('eat')
   };

   function Dog(){

   }

   Dog.prototype=new Animal();

   let dog=new Dog();
   console.log(dog.color);
   dog.eat(); //eat

原型鏈繼承還有個(gè)毛病,就是在創(chuàng)建子類型的實(shí)例時(shí),不能向父類傳遞參數(shù)
第二個(gè)是引用類型值的原型,當(dāng)一個(gè)實(shí)例改變這個(gè)值的時(shí)候,在所有的實(shí)例上都有所表現(xiàn),所以會(huì)用借用構(gòu)造函數(shù)的方式繼承
通過(guò)原型鏈繼承的時(shí)候不能用對(duì)象字面量創(chuàng)建原型方法,這樣會(huì)重寫原型鏈


image.png

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

利用函數(shù)是在特定環(huán)境中執(zhí)行代碼的對(duì)象,使用call或者apply可以讓父類的構(gòu)造函數(shù)在將來(lái)創(chuàng)建的新對(duì)象里執(zhí)行

super.call(this)//其實(shí)這個(gè)this指的就是當(dāng)前的對(duì)象,
//因?yàn)橛胣ew 構(gòu)造出來(lái)的實(shí)例,會(huì)把this指向該實(shí)例本身,所以

function Father(name) {
        this.name=name
    }

    function Child(age) {
        Father.call(this,'小黃')
        this.age=age;
    }
    let child=new Child(19)
    console.log(child);//Child {name: "小黃", age: 19}

借用構(gòu)造函數(shù)模式也存在一些問(wèn)題,方法都在構(gòu)造函數(shù)中定義,所以函數(shù)就沒(méi)發(fā)重用了,而且在父類的原型中定義的方法,在子類中都是不可見(jiàn)的,因?yàn)橹皇抢^承了父類的構(gòu)造函數(shù)中的方法,所以借用構(gòu)造函數(shù)不會(huì)單獨(dú)使用

3、組合繼承

這個(gè)繼承方式的思路是,講原型鏈繼承和借用構(gòu)造函數(shù)繼承組合到一起,使用原型鏈對(duì)原型屬性和方法的繼承,通過(guò)借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承

function Father(name) {
        this.name=name
    }
     Father.prototype.sayName=function () {
         console.log(this.name);
     }
    function Child(name,age) {
        Father.call(this,name)
        this.age=age;
    }
    Child.prototype=new Father();
    Child.prototype.sayAge=function(){
        console.log(this.age);
    }
    let child1=new Child('xiao',13);
        child1.sayName();
        child1.sayAge()

    let child2=new Child('big',14);
        child2.sayName()
         child2.sayAge();

父類的構(gòu)造函數(shù)定義了一個(gè)name 屬性,父類的原型上定義 了一個(gè)sa yName()的方法,子類構(gòu)造函數(shù)在調(diào)用父類構(gòu)造函數(shù)的時(shí)候傳入了name參數(shù),然后又定義了自己的屬性age,然后將父類的實(shí)例賦給了子類的原型,又在子類的原型上定義了sayAge()方法,這樣子類的不同實(shí)例就可以分別擁有自己的屬性和使用一樣的方法了

4、原型式繼承

借助原型,基于已有的對(duì)象創(chuàng)建新的對(duì)象

 let person={
            name:"小紅",
            age:13
        }
 let antherPerson=Object.create(person)
         antherPerson.name="小黑"
         antherPerson.age=15
也可以這樣寫
 let person={
            name:"小紅",
            age:13
        }

        let antherPerson=Object.create(person,{
            name:'小黑'
        })

在沒(méi)有必要?jiǎng)?chuàng)建構(gòu)造函數(shù)的時(shí)候,只是想讓一個(gè)對(duì)象和另一個(gè)對(duì)象保持類似的情況下這種方法就是可以了,不過(guò)引用類型還是會(huì)共享,這相當(dāng)于是對(duì)象的淺拷貝

5、寄生式繼承

 function object(o) {
             function F() {}
             o.prototype=F;
             return new F();
         }
        function createPerson(original){
            let clone=object(original);//通過(guò)調(diào)用函數(shù)創(chuàng)建一個(gè)新的對(duì)象
            clone.say=function () {
                console.log('hi')  //以某種方式增強(qiáng)這個(gè)對(duì)象
            }
            return clone;//返回這個(gè)對(duì)象
        }

let person={
            name:"小紅",
            age:13
        }

      let anotherPerson=createPerson(person);
         anotherPerson.say()

上面代碼中基于person 返回另一個(gè)新對(duì)象,這個(gè)對(duì)象擁有person的所有屬性和方法,還有自己的say()方法
但是寄生式繼承的方式為對(duì)象添加函數(shù)也不能復(fù)用,這樣會(huì)降低效率,和構(gòu)造函數(shù)模式類似

6、寄生組合式繼承

由于組合式繼承會(huì)調(diào)用兩次父類的構(gòu)造函數(shù),第一次是在創(chuàng)建子類原型的時(shí)候,第二次是調(diào)用子類構(gòu)造函數(shù)內(nèi)部調(diào)用父類的時(shí)候,
在第一次調(diào)用父類構(gòu)造函數(shù)的時(shí)候,Child.prototype會(huì)得到一個(gè)name 屬性,它是父類的實(shí)例屬性,不過(guò)現(xiàn)在在子類的原型中,
在調(diào)用子類構(gòu)造函數(shù)的時(shí)候,又一次調(diào)用父類的構(gòu)造函數(shù),不過(guò)這次又在新對(duì)象上創(chuàng)建了實(shí)例屬性name,這個(gè)屬性就屏蔽了原型中的的同名屬性,為了解決這個(gè),就用寄生組合繼承

function Father(name) {
        this.name=name
    }
     Father.prototype.sayName=function () {
         console.log(this.name);
     }
    function Child(name,age) {
        Father.call(this,name)//第二次調(diào)用父類構(gòu)造函數(shù)
        this.age=age;
    }
    Child.prototype=new Father();//第一次調(diào)用
    Child.prototype.constructor=Child

寄生組合式繼承的思想:通過(guò)借用構(gòu)造函數(shù)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法,不必為了指定子類型的原型而調(diào)用構(gòu)造函數(shù),我們只需要一個(gè)父類原型的副本,

function Animal(color){
     this.color = color
 }
 function Dog(color, name){
     Animal.call(this, color) // 或者 Animal.apply(this, arguments)
     this.name = name
 }

 function temp(){}
 temp.prototye = Animal.prototype //父類原型的副本
 Dog.prototype = new temp()

 Dog.prototype.constuctor = Dog  //把原型中的constrcutor指向子類的構(gòu)造函數(shù)

 var dog = new Dog('黃色','小黃')

最優(yōu)的繼承就是寄生組合式繼承

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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