Wisdom a Web Developer

Js之组合继承

2019-05-08
wisdom

前面我们介绍了原型链继承,与构造函数继承,但是都有他们的缺点

原型链继承:共享的原型属性容易被修改,在创建子类型的实例时,不能向超类传参数,不能实现多继承等等。

构造函数继承:生成额外的副本占用额外的内存,因此不能实现函数复用等。

下面让我我们看看二者的结合组合继承

(一) 结合原型链继承与构造函数继承

原型链继承会改变引用属性,而构造函数会添加额外的副本。一般来说公用的方法是不需要额外的副本的。

所以我们可以将公共的方法,挂载到父类的原型对象上去,实现方法复用,然后子类通过原型链继承,就能调用这些方法啦?~

例子:

    //父类:人
    function Person () {
      this.head = '脑袋瓜子';
      this.emotion = ['', '', '', '']; //人都有喜怒哀乐
    }
    //将 Person 类中需共享的方法放到 prototype 中,实现复用
    Person.prototype.eat = function () {
      console.log('吃吃喝喝');
    }
    Person.prototype.sleep = function () {
      console.log('睡觉');
    }
    Person.prototype.run = function () {
      console.log('快跑');
    }
    //子类:学生,继承了“人”这个类
    function Student(studentID) {
      this.studentID = studentID;
      Person.call(this);
    }
    
    Student.prototype = new Person();  //此时 Student.prototype 中的 constructor 被重写了,会导致 stu1.constructor === Person
    Student.prototype.constructor = Student;  //将 Student 原型对象的 constructor 指针重新指向 Student 本身
    
    var stu1 = new Student(1001);
    console.log(stu1.emotion); //['喜', '怒', '哀', '乐']
    
    stu1.emotion.push('');
    console.log(stu1.emotion); //["喜", "怒", "哀", "乐", "愁"]
    
    var stu2 = new Student(1002);
    console.log(stu2.emotion); //["喜", "怒", "哀", "乐"]
    
    stu1.eat(); //吃吃喝喝
    stu2.run(); //快跑
    console.log(stu1.constructor);  //Student

首先,我们将 Person 类中需要复用的方法提取到 Person.prototype 中,然后设置 Student 的原型对象为 Person 类的一个实例,

这样 stu1 就能访问到 Person 原型对象上的属性和方法了。

其次,为保证 stu1 和 stu2 拥有各自的父类属性副本,我们在 Student 构造函数中,还是使用了 Person.call ( this ) 方法。

如此,结合原型链继承和借用构造函数继承,就完美地解决了之前这二者各自表现出来的缺点。

  组合继承是javascript最常用的继承模式,不过,它也有自己的不足:组合继承无论在什么情况下,都会调用两次父类构造函数

一次是在创建子类原型的时候,另一次是在子类构造函数内部.子类最终会包含父类对象的全部实例属性,但我们不得不在调用子类构造函数时重写这些属性。

如何避免这一问题呢,那么请看寄生组合式继承


Similar Posts

Comments

隐藏