• js继承


    比如,现在有一个"动物"对象的构造函数。

      function Animal(){
        this.species = "动物";
      }
    

    还有一个"猫"对象的构造函数。

      function Cat(name,color){
        this.name = name;
        this.color = color;
      }
    

    怎样才能使"猫"继承"动物"呢?

    一:原型链继承

    如果 "猫"的prototype对象,指向一个Animal的实例 ,那么所有"猫"的实例,就能继承Animal了。

      Cat.prototype = new Animal();
    
      Cat.prototype.constructor = Cat;
    
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物
    
    或:
    
        Cat.prototype = Animal.prototype;
      Cat.prototype.constructor = Cat;
      // 任何对Cat.prototype的修改,都会反映到Animal.prototype
    

    优点:

    1. 父类原型中(Cat.prototype)可以动态增加属性和方法,子类(cat1)都会继承

    缺点:

    1. 父类为子类增加属性和方法必须写在Cat.prototype = new Animal()之后
    2. 所有继承的方法都共享的(在Cat.prototype这一个内存中)
    3. 无法实现多继承
    4. 无法传参

    解析

    代码的第一行,我们将Cat的prototype对象指向一个Animal的实例。

      Cat.prototype = new Animal();
    

    它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。但是,第二行又是什么意思呢?

      Cat.prototype.constructor = Cat;
    

    原来,任何一个prototype对象都有一个constructor属性,指向它的构造函数
    Cat.prototype = new Animal()这一行,使Cat.prototype.constructor由Cat指向了Animal。

      alert(Cat.prototype.constructor == Animal); //true
    

    更重要的是,每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性

      alert(cat1.constructor == Cat.prototype.constructor); // true
    

    因此,在运行 Cat.prototype = new Animal() 这一行之后,cat1.constructor也指向Animal!

      alert(cat1.constructor == Animal); // true
    

    这显然会导致继承链的紊乱(cat1明明是用构造函数Cat生成的),因此我们必须手动纠正,将Cat.prototype对象的constructor值改为Cat。这就是第二行的意思。

    这是很重要的一点,编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象
    那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。

       o.prototype = {};
       
      o.prototype.constructor = o;
    

    二: 借用构造函数

    使用callapply方法,将父对象的构造函数绑定在子对象上
    即在子对象构造函数中加一行 Animal.apply(this, arguments);

      function Cat(name,color){
    
        Animal.apply(this, arguments);
    
        this.name = name;
        this.color = color;
    
      }
    
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物
    

    优点

    1. 解决了子类方法共享的问题(不在一个内存中)
    2. 可以实现多继承
    3. 可以传参

    缺点

    1. 创建的cat1实例仅是子类Cat的实例,不是父类Animal的实例
    2. 只能继承父类构造函数内的属性和方法,不能继承父类原型中的属性和方法
    3. 属性和方法没有复用,占用内存

    三: 组合式继承

      function Cat(name,color){
    
        Animal.apply(this, arguments);  //第一次调用父类构造函数
    
        this.name = name;
        this.color = color;
      }
      
      Cat.prototype = new Animal();  ///第二次调用父类构造函数(new调用的)
      Cat.prototype.constructor = Cat;
    
      var cat1 = new Cat("大毛","黄色");
      alert(cat1.species); // 动物
    

    优点
    结合上面两种优点

    缺点

    1. 父类构造函数调用了两次
    2. 容易发生同名覆盖,cat1的构造函数和原型中都存在species属性

    四: 原型式继承

    由于"直接继承prototype"存在上述的缺点,所以就有这种方法,利用一个空对象作为中介。

      var F = function(){};
    
      F.prototype = Animal.prototype;
    
      Cat.prototype = new F();
    
      Cat.prototype.constructor = Cat;
    

    F是空对象,所以几乎不占内存。这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象。

      alert(Animal.prototype.constructor); // Animal
    

    我们将上面的方法,封装成一个函数,便于使用。(Object.creat()实现)

      function extend(Child, Parent) {
    
        var F = function(){};
    
        F.prototype = Parent.prototype;
    
        Child.prototype = new F();
    
        Child.prototype.constructor = Child;
    
        Child.uber = Parent.prototype;
    
      }
    

    使用的时候,方法如下

      extend(Cat,Animal);
    
      var cat1 = new Cat("大毛","黄色");
    
      alert(cat1.species); // 动物
    

    这个extend函数,就是YUI库如何实现继承的方法。

  • 相关阅读:
    序列
    笔算开方法
    笔算开方法
    【AFO】闷声发大财
    P1092 虫食算[搜索]
    数据结构总结
    P1486 [NOI2004]郁闷的出纳员[权值线段树]
    P1850 换教室[dp+期望]
    P4281 [AHOI2008]紧急集合 / 聚会[LCA]
    P5021 赛道修建[贪心+二分]
  • 原文地址:https://www.cnblogs.com/topyang/p/11397137.html
Copyright © 2020-2023  润新知