继承

继承

  • 许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,实现继承则继承实际的方法。由于ES中函数没有签名(也是无重载的原因),无法实现接口继承,只支持实现继承。
  • 原型链:利用原型让一个引用类型继承另一个引用类型的属性和方法。
  • 构造函数、原型和实例三者关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针

实现继承的方法

  • 父类

      //定义一个鸟类
      function Bird(name) {
          //属性
          this.name = name || 'Bird'
          //实例方法
          this.fly = function() {
              console.log(this.name + '正在飞!')
          }
      }
      //原型方法
      Bird.prototype.eat = function(food) {
          console.log(this.name + '正在吃' + food);
      };
    
  1. 原型链继承:将父类的实例作为子类的原型

     function Pigeon() {
         // 不能放到构造器
     }
     Pigeon.prototype = new Bird();
     Pigeon.prototype.name = 'Pigeon';
     //检测
     var pigeon = new Pigeon();
     console.log(pigeon.name);
     console.log(pigeon.fly());
     console.log(pigeon.eat(rice))
    
  • 缺点:
  1. 要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
  2. 无法实现多继承
  3. 来自原型对象的引用属性是所有实例共享的,针对父类实例引用类型成员的更改,会通过影响其他子类实例
  4. 创建子类实例时,无法向父类构造函数传参
  1. 构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

     function Pigeon(name) {
         Bird.call(this);
         this.name = 'Pigeon' || name;
     }
     //检测
     var pigeon = new Pigeon();
     console.log(pigeon.name);
     console.log(pigeon.fly());//只能继承实例方法
     console.log(pigeon instanceof Bird);// false,不是父类的实例,只是子类的实例
    
  • 缺点:
  1. 实例并不是父类的实例,只是子类的实例
  2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
  3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
  1. 组合继承:通过调用父类构造器,继承父类的属性并保留传参的有优点,然后将父类实例作为子类原型,实现函数复用

     function Pigeon(name) {
         Bird.call(this);//一份实例
         this.name = 'Pigeon' || name;
     }
     Pigeon.prototype = new Bird();//另一份实例
     Pigeon.prototype.constructor = Cat;//组合继承需要修复构造函数的指向
     //检测
     var pigeon = new Pigeon();
     console.log(pigeon.name);
     console.log(pigeon.fly());
    
  • 缺点:
  1. 调用了两次父类构造器,生成了两份实例
  1. 寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样在调用两次父类构造函数的时候,就不会初始化两次实例方法/属性,避免了组合继承的缺点

     function Pigeon(name) {
         Bird.call(this);
         this.name = 'Pigeon' || name;
     }
     (function() {
         // 创建一个没有实例方法的类
         var Super = function() {};
         Super.prototype = Bird.prototype;
         // 将实例作为子类的原型
         Pigeon.prototype = new Super();
     })();
     Pigeon.prototype.constructor = Pigeon;//修复指向构造函数的指针
     //测试
     var pigeon = new Pigeon();
     console.log(pigeon.name);
     console.log(pigeon.fly());
     console.log(pigeon.eat(rice));
     console.log(pigeon instance of Pigeon);/true
     console.log(pigeon instance of Bird);//true
    
posted @ 2018-03-23 14:53  YFIFE  阅读(154)  评论(0编辑  收藏  举报