JS -- (11) 继承

251 阅读3分钟

大致有6种继承,各有利弊吧

  • 原型链继承
  • 盗用构造函数
  • 组合继承 【原型链 + 盗用构造函数】
  • 原型式继承 【适用于不需要单独创建构造函数,但仍需在对象之间共享信息的场合】
  • 寄生式继承 【寄生构造函数+工厂模式】拷贝原对象、增强副本、返回
  • 寄生式组合继承
<1> 原型链继承

让儿子构造函数的原型等于父亲的实例对象

Child.prototype = new Parent();

缺点:

  • 所有实例共享同一个引用类型的属性
function Parent () {
    this.names = ['kevin', 'daisy'];
}

function Child () {

}

Child.prototype = new Parent();

var child1 = new Child();

child1.names.push('yayu');

console.log(child1.names); // ["kevin", "daisy", "yayu"]

var child2 = new Child();

console.log(child2.names); // ["kevin", "daisy", "yayu"]
  • 在创建 Child 的实例时,不能向Parent传参
<2> 盗用构造函数

在儿子构造函数中调用父亲的构造函数,来实现父亲构造函数中的属性!!

注意:

  • 方法都在构造函数中定义
function Parent () {
    this.names = ['kevin', 'daisy'];
}

function Child () {
    Parent.call(this);
}

var child1 = new Child();

优点:

  • 避免了引用类型的属性被所有实例共享
  • 可以在 Child 中向 Parent 传参

缺点:

  • 每次创建实例都会创建一遍方法。(且继承不到父亲原型中的方法!!!!)
<3> 组合继承 【原型链+盗用构造函数】

使用原型链继承原型上的属性和方法,使用盗用构造函数继承实例自己的属性!!!

注意:

  • 此时就可以把方法定义到原型对象上了
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {

    Parent.call(this, name);
    
    this.age = age;

}

Child.prototype = new Parent();
Child.prototype.constructor = Child;

var child1 = new Child('kevin', '18');

缺点:

  • 效率问题,父类构造函数被调用了两次!!!
<4> 原型式继承 【不需要单独创建子类和父类构造函数的原型链继承,也不需要再 new 出来子类实例对象,直接可以得到实例对象】

实现对象间属性和方法的共享,不需要单独创建父类、子类构造函数,也不需要再 new 出来子类的实例对象。思路就是:创建一个空的构造函数 F(),把该构造函数的原型指向要继承的对象。然后返回 new F()

function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}

缺点:

  • 所有实例共享同一个引用类型的属性
<5> 寄生式继承 【工厂模式:拷贝父对象,增强副本,返回副本】

基本思路 类似于寄生构造函数和工厂模式:创建一个实现继承的函数,在函数中先拷贝源对象,然后增强副本,然后返回新对象!!

function createObj (o) {
    var clone = Object.create(o);
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}

缺点:

  • 跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
<6> 寄生组合式模式 【解决了组合继承,父类构造函数need new两次!!】

基本思路 (1)父类方法继承: 不通过调用父类构造函数给子类原型赋值,而是获得父类原型的一个副本,就是用寄生式继承来继承父类原型,然后将返回的新对象赋值给子类的原型。(即把子类的原型指向父类的原型) (2) 父类属性继承: 盗用构造函数来继承父类的属性!!!

function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}


// 寄生式+原型式 继承方法

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

function prototype(Child, Parent) {
    var prototype = object(parent.prototype);
    prototype.constructor = Child;
    Child.prototype = prototype;
}

// 当我们使用的时候:
prototype(Child, Parent);