function inheritObject(obj){ function F(){}; F.prototype = obj; return new F(); } //传递参数 child,parent 子类父类 function inheritPrototype(child,parent){ //复制一份父类的原型副本保存在变量中; var fatherProto = inheritObject(father.prototype); //修正因为重写子类原型导致子类的constructor属性被修改; fatherProto.constructor = child; //设置子类的原型 child.prototype = fatherProto; } //声明父类 function Father(val){ this.companies =['bigo','yy','uc'] this.val = val; } //声明父类原型方法 Father.prototype.getValue = function(){ console.log(this.val); } //声明子类 function Child(val,newVal){ //构造函数式继承 Father.call(this,val); this.newVal = newVal; } //类式继承 Child.prototype = new Father(); inheritPrototype(Child,Father); //声明子类原型方法 Child.prototype.getNewValue = function(){ console.log(this.newVal); }
1.在构造函数继承中我们已经调用了父类的构造函数,还差一个原型的副本
2.通过原型继承得到副本,但是这时候fatherProto的constructor需要指向子类。
3.最后将副本fatherProto赋给子类的原型prototype。
总的来说,就是既要构造函数,又要原型继承,但是又避免了组合继承的两次调用父类构造函数的问题,最大的改变式对子类原型赋予的式父类原型的一个引用。
var instanceA = new Child("fatherA","childA"); instanceA.companies.push('nemo'); console.log(instanceA.companies); //['bigo','yy','uc','nemo'] instanceA.getValue(); //fatherA instanceA.getNewValue(); //childA var instanceB = new Child("fatherB","childB"); console.log(instanceA.companies); //['bigo','yy','uc'] instanceB.getValue(); //fatherB instanceB.getNewValue(); //childB
注意点:
此时子类如果需要添加原型方法,必须通过prototype点语法一个个添加,否则会覆盖掉继承父类的原型对象。
ES6 新增了Class语法,Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
Class 继承
class Parent { constructor(value) { this.val = value } getValue() { console.log(this.val) } } class Child extends Parent { constructor(value) { super(value) } } let child = new Child(1) child.getValue() // 1 child instanceof Parent // true
class 实现继承的核心在于使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super,因为这段代码可以看成 Parent.call(this, value)。
如果子类没有定义constructor方法,这个方法会被默认添加。