04.第6章:面向?qū)ο蟮某绦蛟O(shè)計(jì)

1.構(gòu)造函數(shù)

任何一個(gè)函數(shù)只要被new使用了,就是構(gòu)造函數(shù)。
構(gòu)造函數(shù)用來存放每一個(gè)實(shí)例自己具有的屬性和方法。

<script>
    function Person(name,age){
        //每一個(gè)實(shí)例有自己的名字和年齡,而不是所有的實(shí)例共享同一個(gè)名字和年齡
        this.name=name;
        this.age=age;
    }
    let p=new Person('abc',20);
    console.log(p);
</script>

可以看到上面創(chuàng)建的P實(shí)例對象,具有__proto__屬性,指向的對象就是原型對象。同時(shí)構(gòu)造函數(shù)Person中prototype屬性指向的也是該原型對象,完全全等。

2.原型對象原型鏈

  • 任何一個(gè)構(gòu)造函數(shù)在創(chuàng)建的時(shí)候,都有一個(gè)prototype屬性,該屬性指向原型對象。
  • 任何一個(gè)引用對象(數(shù)組、對象、函數(shù)),都有一個(gè)__proto__屬性,該屬性也指向原型對象。
  • 原型對象中有constructor屬性,指向構(gòu)造函數(shù);有__proto__屬性指向父類的原型對象。

原型對象中有一個(gè)constructor屬性,指向構(gòu)造函數(shù)Person(name,age)。
原型對象也有__proto__,指向其父類的原型對象,這里是指向Object的原型對象。

原型對象用來存放所有實(shí)例共享的屬性和方法。

<script>
    function Person(name,age){
        //每一個(gè)實(shí)例有自己的名字和年齡,而不是所有的實(shí)例共享同一個(gè)名字和年齡
        this.name=name;
        this.age=age;
    }
   //在原型對象中創(chuàng)建共享的方法
    Person.prototype.getName=function(){
      return this.name;
    };

    let p=new Person('abc',20);
    //當(dāng)在實(shí)例中找不到調(diào)用的屬性或方法時(shí),就會沿著__proto__屬性指向的原型對象一層層的向上查找。(原型鏈)
    //這里調(diào)用的是原型對象中的方法
    console.log('name:'+p.getName());
    console.log(p);

    //在p實(shí)例對象的__proto__的__proto__中查找,
    //也就是Object構(gòu)造函數(shù)的prototype指向的原型對象,
    //這個(gè)Object.prototype.__proto__===null。避免死循環(huán)
    p.toString();
</script>

3.instanceof

用于判斷引用類型的實(shí)例是屬于哪個(gè)構(gòu)造函數(shù)的方法。

原理:

  • 判斷實(shí)例的__proto__指向的原型對象(隱試原型)與構(gòu)造函數(shù)的prototype屬性所指向的原型對象(顯式原型)是否是同一個(gè)。


  • 子類型的實(shí)例instanceof父類型的構(gòu)造函數(shù),也會返回true


  • 要更加詳細(xì)的識別是子類型的實(shí)例
實(shí)例對象.__proto__.constructor===構(gòu)造函數(shù)

4.繼承的實(shí)現(xiàn)方式

1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承

<script>
    /*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
    function Father(name,age){
        this.name=name;
        this.age=age;
    }
    //父類原型對象中的方法
    Father.prototype.getName=function(){
      console.log(this.name);
    };

    //父類原型對象中的方法
    Father.prototype.getAge=function(){
        console.log(this.age);
    };

    function Son(name,age){
        Father.call(this,name,age);
    }

    let son =new Son('abc',13);
    console.log(son);

</script>

缺點(diǎn):
只能繼承父類實(shí)例的屬性和方法,不能繼承父類原型對象中的屬性和方法。

2.使用原型鏈繼承

<script>
    /*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
    function Father(name,age){
        this.name=name;
        this.age=age;
    }
    //父類原型對象中的方法
    Father.prototype.getName=function(){
      console.log(this.name);
    };

    //父類原型對象中的方法
    Father.prototype.getAge=function(){
        console.log(this.age);
    };

    function Son(name,age){
        //Father.call(this,name,age);
    }

    //使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
    //為父類的一個(gè)實(shí)例。
    Son.prototype=new Father();


</script>

缺點(diǎn):父類所有的屬性和方法,在子類中都成了原型對象中的屬性和方法。

3.組合式繼承
使用call方法來繼承構(gòu)造函數(shù)中的屬性和方法,
使用原型鏈來繼承原型對象的屬性和方法。

<script>
    /*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
    function Father(name,age){
        this.name=name;
        this.age=age;
    }
    //父類原型對象中的方法
    Father.prototype.getName=function(){
      console.log(this.name);
    };

    //父類原型對象中的方法
    Father.prototype.getAge=function(){
        console.log(this.age);
    };

    function Son(name,age){
        Father.call(this,name,age);
    }

    //使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
    //為父類的一個(gè)實(shí)例。
    Son.prototype=new Father();


</script>

缺點(diǎn):子類的原型對象中有父類構(gòu)造函數(shù)中的屬性和方法,同時(shí)子類的實(shí)例中也有父類構(gòu)造函數(shù)中的屬性和方法,繼承了兩次。

4.改進(jìn)的組合繼承1

<script>
    /*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
    function Father(name,age){
        this.name=name;
        this.age=age;
    }
    //父類原型對象中的方法
    Father.prototype.getName=function(){
      console.log(this.name);
    };

    //父類原型對象中的方法
    Father.prototype.getAge=function(){
        console.log(this.age);
    };

    function Son(name,age){
        Father.call(this,name,age);
    }

    //使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
    //為父類構(gòu)造函數(shù)的原型對象。
    Son.prototype=Father.prototype;


</script>

缺點(diǎn):用了父類的原型對象,父類原型對象中的constructor指向父類的構(gòu)造函數(shù)。

5.改進(jìn)的組合繼承2

<script>
    /*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
    function Father(name,age){
        this.name=name;
        this.age=age;
    }
    //父類原型對象中的方法
    Father.prototype.getName=function(){
      console.log(this.name);
    };

    //父類原型對象中的方法
    Father.prototype.getAge=function(){
        console.log(this.age);
    };

    function Son(name,age){
        Father.call(this,name,age);
    }

    //使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
    //為父類構(gòu)造函數(shù)的原型對象的副本。
    Son.prototype=Object.create(Father.prototype);
    //設(shè)置constructor為父類的構(gòu)造函數(shù)
    Son.prototype.constructor=Son;


</script>



5.new關(guān)鍵字的執(zhí)行過程

<script>
    function Person(name,age) {
        this.name=name;
        this.age=age;
    }

    function mynew(fn,name,age){
        //1.創(chuàng)建一個(gè)繼承自構(gòu)造函數(shù)原型對象的空對象
        let o=Object.create(fn.prototype);
        //2.調(diào)用構(gòu)造函數(shù)為該對象賦值
        let k=fn.call(o,name,age);
        //3.如果構(gòu)造函數(shù)中返回的k是對象,則返回k
        if(typeof k==='object')
            return k;
        //4.如果不是返回o
        else
            return o;

    }

    let person=mynew(Person,'abc',13);
    console.log(person);

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

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

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