js寄生组合式继承



转载自知乎: 如何理解javascript中寄生组合式继承?

其实《JavaScript高级程序设计》这本书中已经有完整代码了,只要把代码读懂就知道这个继承是怎么回事。

首先,在js中,给对象定义属性有两种方式:
//通过执行构造函数设置属性
function A(){
    this.a = 1;
}
//通过原型设置属性
A.prototype.b = 1;

所以:
一个类Sub要继承另一个类Super,需要继承父类的prototype下的属性,还要执行一下父类的构造函数。

一个类Sub要继承另一个类Super,既要通过原型链实现对原型属性和方法的继承,又要通过在子类构造函数内调用父类构造函数实现对实例属性的继承。

1. 继承prototype下的属性
上面可以看到,Super类的prototype下的属性是没有被继承的,因此下面还需要继承这一部分。
直接「=」肯定不行,因为Sub.prototype中修改属性后,不能影响Super.prototype里面的对象,即不能Sub.prototype=Super.prototype。

首先写一个创建对象副本的方法

function object(o){
    function A(){}
    A.prototype = o
    var ox = new A()
    return ox
}

上面的函数得到的对象ox,拥有了对象o的全部属性(在原型链上),而修改ox的属性,不会影响到o,相当于把o复制了一份。

原型式继承就是上面的“object”函数,在很多类库源码中都能发现它的身影
简单而言,原型式继承就是不用实例化父类了,直接实例化一个临时副本实现了相同的原型链继承。(即子类的原型指向父类副本的实例从而实现原型共享)

//tips:总所周知,原型链继承是子类的原型指向父类的实例从而实现原型共享,而原型式继承是子类的原型指向父类副本的实例从而实现原型共享。

ECMAScirpt 5通过新增Object.create()方法规范化了原型式继承。

使用object方法,就可以将Super.prototype的属性「复制」到Sub.prototype上了,当然这儿还需要修正一下constructor的指向。

function inherit(subType,superType){ 
  var prototype=Object.create(superType.prototype); 
  prototype.constructor=subType; 
  subType.prototype=prototype; 
} 


2. 分别执行父类和子类的构造函数,继承这部分下的属性:
//父类
function Super(){
this.sss=1
}
//子类
function Sub(){
//arguments是Sub收到的参数,将这个参数传给Super
Super.apply(this, arguments)
}
//实例
sub = new Sub()

Super.apply(this, arguments)这一句,将Super类作为一个普通函数来执行,但是Super类的this被换成了Sub类的this,Sub收到的参数也传给了Super
最后执行结果相当于sub.sss=1



附上各种继承方式的特点和优缺点


曾经一段时间因为javascript关于类实现继承的不规范,导致各种各样实现继承的代码;而实际上不管代码怎么变,继承都基于两种方式:
1.通过原型链,即子类的原型指向父类的实例从而实现原型共享。
2.借用构造函数,即通过js的apply、call实现子类调用父类的属性、方法;

      原型链方式可以实现所有属性方法共享,但无法做到属性、方法独享(例如Sub1修改了父类的函数,其他所有的子类Sub2、Sub3...想调用旧的函数就无法实现了);
      而借用构造函数除了能独享属性、方法外还能在子类构造函数中传递参数,但代码无法复用。总体而言就是可以实现所有属性方法独享,但无法做到属性、方法共享(例如,Sub1新增了一个函数,然后想让Sub2、Sub3...都可以用的话就无法实现了,只能Sub2、Sub3...各自在构造函数中新增)。
      组合继承就是把以上两种继承方式一起使用,把共享的属性、方法用原型链继承实现,独享的属性、方法用借用构造函数实现,所以组合继承几乎完美实现了js的继承;为什么说是“几乎”?因为认(dan)真(teng)的geek们发现组合继承有一个小bug,实现的时候调用了两次超类(父类),性能上不合格啊有木有!怎么解决呢?于是“寄生继承”就出来了。

        寄生继承(原型式继承)就是不用实例化父类了,直接实例化一个临时副本实现了相同的原型链继承。(即子类的原型指向父类副本的实例从而实现原型共享)

      “寄生组合继承”用了“寄生继承”修复了“组合继承”的小bug,从而让js完美实现继承了。


实例代码:

function SuperType(name,colors){ 
   this.name=name; 
   this.colors=colors; 
} 
SuperType.prototype.getSuperProperty=function(){ return this.name; } 

function SubType(job,name,colors){ 
   SuperType.call(this,name,colors); 
   this.job=job; 
} 
SubType.prototype.getSubPrototype=function(){ return this.job; } 

function inherit(subType,superType){ 
   var prototype=Object.create(superType.prototype); 
   prototype.constructor=subType; 
   subType.prototype=prototype; 
} 
inherit(SubType,SuperType); 

var instance=new SubType("doctor","John",["red","green"]); 
console.log(instance.getSubPrototype());    //输出"doctor"
console.log(instance.getSuperProperty());   //输出"John",成功调用在父类原型定义的方法

属性继承代码是SuperType.call(this,name,colors); 

原型继承代码是inherit(SubType,SuperType); 







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值