面向对象中的继承扩展0219

301 阅读5分钟

1.原型链继承

(1)图示如下: 子类继承父类的属性和方法(目的让子类的实例可以调取父类中的属性和方法)

方案分析:CHILD.prototype = new PARENT() 每个函数自带属性prototype,实例自带属性__proto__

(2)代码举例


       //构造函数Person
        function Person(){
            this.name = "xiaomingming";
            this.pets =["maomao","gougou"];

        }
        Person.prototype.run = function(){
            console.log('runrunrun')
        }
        function Stu(){
            this.num = "bengbeng"
        }
        <!--以下是核心步骤-->
        //1.构造父类的实例
        var p = new Person();
        // 2.设置子类的原型对象
        Stu.prototype = p;
        // 3.修复constructor指针
        Stu.prototype.constructor = Stu;

        //全部继承
        var stu = new Stu();
        console.log(stu);
        console.log(stu.num);

    console.log(stu.name);
    console.log(stu.pets);

问题引入

接以上代码:
  //构造函数Person
    <script>
        function Person(){
            this.name = "xiaomingming";
            this.pets =["maomao","gougou"];

        }
        Person.prototype.run = function(){
            console.log('runrunrun')
        }
        function Stu(){
            this.num = "bengbeng"
        }
        <!--以下是核心步骤-->
        //1.构造父类的实例
        var p = new Person();
        // 2.设置子类的原型对象
        Stu.prototype = p;
        // 3.修复constructor指针
        Stu.prototype.constructor = Stu;

        //全部继承
        var stu = new Stu();
        var stu2 = new Stu();
    </script>    
    <script>
        1.
        stu.name = "Jay"
        console.log(stu)
        console.log(stu2)
        2.
        var pets = stu.pets;
        pets.push('huhu')

        console.log(stu)
        console.log(stu2)

    </script>

上面结果

对比我们可以发现对于简单类型name互不影响,stu2中并没有name熟性,复杂类型pets却是共享了(修改pets,新创造的实例stu2受到影响)

接下来值得注意:

1.子类方法要在实现继承后去定义方法2.子类可以重写父类上的属性和方法 代码示例1:

  //构造函数Person
        function Person(){
            this.name = "xiaomingming";
            this.pets =["maomao","gougou"];
        }
        Person.prototype.run = function(hi){
            this.hi = 'hi'
            console.log('runrunrun')
        }
        function Stu(){
            this.name = 'xinming'
            this.num = "bengbeng"
        }
        Stu.prototype.eat=function(){
            console.log('我是继承前定义的eat')
        }
        //1.构造父类的实例
        var p = new Person();
        // 2.设置子类的原型对象
        Stu.prototype = p;
        // 3.修复constructor指针
        Stu.prototype.constructor = Stu;
        //全部继承
        var stu = new Stu();
        stu.run();
        // stu.eat();
        // 1.
        stu.name = "Jay"
        // 2.
        var pets = stu.pets;
        pets.push('huhu')
        var stu2 = new Stu();
        stu2.run();
        console.log(stu)
        console.log(stu2)

报错:

代码示例2:

     //构造函数Person
        function Person(){
            this.name = "xiaomingming";
            this.pets =["maomao","gougou"];
        }
        Person.prototype.run = function(hi){
            this.hi = 'hi'
            console.log('runrunrun')
        }
        function Stu(){
            this.name = 'xinming'
            this.num = "bengbeng"
        }
        //1.构造父类的实例
        var p = new Person();
        // 2.设置子类的原型对象
        Stu.prototype = p;
        // 3.修复constructor指针
        Stu.prototype.constructor = Stu;
        Stu.prototype.eat=function(){
            console.log('我是继承后定义的eat')
        }
        Stu.prototype.run=function(bye){
            console.log('我是继承后定义的run')
        }    
        //全部继承
        var stu = new Stu();
        stu.run();
        stu.eat();
        1.
        stu.name = "Jay"
        // 2.
        var pets = stu.pets;
        pets.push('huhu')
        var stu2 = new Stu();
        stu2.run();
        console.log(stu)
        console.log(stu2)  

总结: 特点1:父类中私有的属性和方法最会都变成子类公有的属性和方法。 特点2:子类可以重写父类上的属性和方法(导致子类其他实例受影响)

2.单独采用构造函数实现继承

    function Animal(){
        this.species = "动物";
    }
    Animal.prototype.run=function(){
        console.log('animal原型')
    }
    function Cat(name,color){
        this.name = name;
        this.color = color;
    }
    function Cat(name,color){
        Animal.apply(this, arguments);
        this.name = name;
        this.color = color;
    }

    var cat1 = new Cat("AA猫","黑色");
    alert(cat1.species);    // 动物
    cat1.run()

结果:

原型上的方法和属性并不能继承 js高程原话: 而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结 果所有类型都只能使用构造函数模式。考虑到这些问题,借用构造函数的技术也是很少单独使用的。

构造函数继承总结: 特点:1.CHILD方法中把PARENT当做普通函数执行,让PARENT中的THIS指向CHILD的实例,相当于给CHILD设置了很多私有属性方法 1.只能继承父类私有的属性和方法,(因为是把PARENT当做普通函数执行,和其原型上的属性和方法没有关系) 2.父类私有变成子类私有

关于私有公有我们可以理解为,私有的只是在当前的函数里面起作用,公有的是会依照原型进行继承,是会影响到后续的依靠其创建的实例的属性和方法。

3.在原型继承基础上+借助构造函数继承(解决共享问题)

完整代码:

<script>
        /**
     * 构造函数Person
     */
        function Person(name,pets){
            this.name = name;
            this.pets =pets;

        }
        Person.prototype.run = function(){
            console.log('runrunrun')
        }
        function Stu(num,name,pets){
            Person.call(this,name,pets);//这一句要写在上面防止属性覆盖
            this.num = num;
            //构造函数
        }
         //1.构造父类的实例
        var p = new Person();
        // 2.设置子类的原型对象
        Stu.prototype = p;
        // 3.修复constructor指针
        Stu.prototype.constructor = Stu;
        Stu.prototype.run=function(bye){
            console.log('我是继承后定义的run')
        }    
    </script>
    <script>
        var stu = new Stu('001','xiaoming',['maomao','gougou'])
        var stu2 = new Stu('002','xiaogang',['momo','gogo'])
        stu.run();
        stu2.run();
        console.log(stu)
        console.log(stu2)
    </script>

由上面的调用代码我们可以看出子类Stu的实例继承了父类Person的属性和方法,

另外:

    <script>
    var stu = new Stu('001','xiaoming',['maomao','gougou'])
    stu.pets.push('dudu')
    var stu2 = new Stu('002','xiaogang',['momo','gogo'])
    console.log(stu)
    console.log(stu2)

修改stu的pets,stu2没受到影响。 到此以上:原型链+构造函数=“组合继承”,那么以上代码我们还需要让父类公有的属性方法变成子类公有的属性和方法。

4.寄生组合式继承

我们想到了Object.create(OBJ)创建一个空的对象,让空对象__proto__指向OBJ。 此api存在ie兼容问题,我们可以自己实现,其中一个实现方式为

Object.create = function(obj){
        function Fn(){}
        Fn.prototype = obj
        return new Fn();
    }

此方法用图表示为(绿色线部分):

    Stu.prototype = Object.create(Person.prototype)
    Stu.prototype.constructor = Stu;

完整的代码:

<script>
   function Person(name,pets){
       this.name = name;
       this.pets =pets;
       var jj = 'jj'
   }
   Person.prototype.run = function(){
       console.log('runrunrun')
   }
   function Stu(num,name,pets){
       Person.call(this,name,pets);//这一句要写在上面防止属性覆盖
       this.num = num;
       //构造函数
   }
   //寄生组合继承
   Stu.prototype = Object.create(Person.prototype)
   Stu.prototype.constructor = Stu;
   //以上方法存在兼容性不兼容ie,我们可以自己写create
   Stu.prototype.joke = function(){
       console.log('walking')

   }
   //自己写create
   思路: 创建一个空对象,使空对象的__proto__指向obj
   <!--Object.create = function(obj){-->
   <!--    let oo = {};-->
   <!--    oo.__proto__= obj;-->
   <!--    return oo;-->
   <!--}-->
   <!--对于不识别_proto_的情况:-->
   <!--Object.create = function(obj){-->
   <!--    function Fn(){}-->
   <!--    Fn.prototype = obj-->
   <!--    return new Fn();-->
   <!--}-->

</script>
<script>
   var stu = new Stu('001','xiaoming',['maomao','gougou'])   
   stu.pets.push('dudu')
   var stu2 = new Stu('002','xiaogang',['momo','gogo'])
   stu.run()
   stu2.run()
   stu2.joke()

   console.log(stu)
   console.log(stu2)

</script>