JS—理解组合继承与寄生组合继承(ECS5)

在ES6引入class关键字之前,要实现类的继承关系就得用原型链的方式来编写。

组合继承

通过原型链实现对原型属性和方法的继承,借用构造函数来实现对实例属性的继承。如下:

function SuperType(name) {
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.saySuperName = function() {
        alert(this.name);
    }
    SuperType.prototype.tea = function() {
        alert(this.name);
    }

    function SubType(name, age) {
        SuperType.call(this, name);
        this.age = age;
    }
    SubType.prototype = new SuperType();//子类SubType的原型指向父类SuperType的一个实例
    SubType.prototype.constuctor = SubType;//重置构造函数指针
    SubType.prototype.saySubAge = function() {
        alert(this.age);
    }

    var instance = new SubType("sb", 18);

其中,“重置构造函数指针”是由于上一步的原型对象改变,导致SubType原型对象下的constructor指针指向的是SuperType,所以需要手动重置。

在组合继承中,调用了两次父类的构造函数:

SubType.prototype = new SuperType();//第一次调用,用于子类原型对象的指针所指
SuperType.call(this, name);//当调用SubType的构造函数时,再一次调用了SuperType();
SubType.prototype = new SuperType();//第一次调用,用于子类原型对象的指针所指 SuperType.call(this, name);//当调用SubType的构造函数时,再一次调用了SuperType();

而两次调用,会产生一个问题:子类原型对象上的属性会被子类实例上的属性屏蔽。(由于原型链机制的问题)。如下:

实例instance是SubType类型,它有两个属性name和colors,这两个都源于父类的属性(由于内部调用SuperType.call(this, name)),但是在实例的原型指针_proto_所指向的是SuperType的一个实例(由于调用SubType.prototype =new SuperType()),所以作为父类的一个实例,自然有一份父类的属性name和colors。

而这多出的一份,我们是不需要的。产生这个的原因在于,组合继承是通过父类的一个实例作为子类的一个原型对象。如:子类原型对象->父类实例->父类原型对象。

而我们需要的只是子类原型对象->父类原型对象。

所以寄生组合式继承就由此而生了。

 

寄生组合式继承

function HeritSuperType(name) {
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    HeritSuperType.prototype.sayHeritName = function() {
        alert(this.name);
    }
    HeritSuperType.prototype.echo = function() {
        console.log("nothing");
    }

    function HeritSubType(name, age) {
        HeritSuperType.call(this, name);
        this.age = age;
    }
    inheritPrototype(HeritSubType, HeritSuperType);
    HeritSubType.prototype.sayHeritAges = function() {
        alert(this.age);
    }
    var heritInstance = new HeritSubType("2b", 20);

    function inheritPrototype(subType, superType) {
        let prototype = Object.create(superType.prototype);
        prototype.constructor = subType;
        subType.prototype = prototype;
    }

其中:inheritPrototype(subType, superType)函数是寄生式继承函数,以来包装父类和子类。将父类的原型对象取出,父类原型对象的构造指针指向子类,再由子类的原型对象指向父类原型对象,从而达到子类原型对象->父类原型对象。

注:如组合继承一样,如果不将父类原型对象的构造指针指向子类,就会导致子类原型对象和父类原型对象的构造指针一样。

为了进行更直观的对比,实例化一个父类对象:

var testHeritSuper = new HeritSuperType("3b");//寄生组合式继承的父类实例 

可以看到,父类实例的原型对象是object,拥有自己的一份数据。heritInstance的原型对象是HeritSuperType,这里是用浅复制(Object.create),所以在其原型对象上不会有数据。所以后续给原型添加新方法,会存在(HeritSubType.prototype.sayHeritAges)。

结语

寄生组合式继承,才有其他面向对象语言中的继承意味。如C#中的:、Java中的extend。当然在ES6,JS加入了extend关键字,但这不意味着以原型链方式做出的继承关系就可以不用了解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值