寄生组合式继承,从名字看就可以理解为寄生式继承和组合式继承的结合版,是开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。要了解寄生组合式继承首先从寄生式继承和组合式继承。
组合式继承
组合式继承将原型链和构造函数的技术组合到一起,结合两者的优点,通过原型链实现对原型属性和方法的继承以及借用构造函数来实现对实例属性的继承。拥有以下的优点
- 父类的方法可以被复用
- 父类的引用属性不会被共享
- 子类构建实例时可以向父类传递参数
不过组合式继承中两次调用了父类构造函数,
// 创建父类
let parent = function(name) {
// 父类型的自有属性
this.name = name;
this.hobbies = ['tennis','music','photography']
}
// 添加父类方法
parent.prototype = {
getName() { console.log(this.name) }
}
// 创建子类
let son = function(name,sex) {
//构造函数式继承父类属性,这里是第二次调用父类构造函数
parent.call(this, name);
// 添加子类自己的私有属性
this.sex = sex;
}
// 这里是类式继承子类原型继承父类,是第一次调用父类构造函数
son.prototype = new parent();
// 将构造函数指向自己
son.prototype.constructor = son;
// 添加子类自己的方法
son.prototype.getsex = function () { console.log(this.sex)}
// 创建实例
let sub1 = new son('taec','male')
console.log(sub1)
sub1.getName()
sub1.getsex()
根据上面代码个人理解的原型链如下图所示,如果不对希望有大佬指正下
寄生式继承
创建一个封装基础过程的函数,该函数内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。
// 设置父类自有属性和方法
let parent2 = {
name:'zy',
hobbies:['tennis','music','photography'],
getName:function () {console.log(this.name)}
}
// 这个方法用于创建一个新对象并且连接原型链
function object (obj) {
function F(){}
F.prototype = obj;
return new F ();
}
function createson (o,sex) {
// 传入父类创建个新对象
let newson = object(o)
// 这里增强对象,添加属性和方法
newson.sex = sex
newson.getsex = function () { console.log(this.sex) }
// 返回对象
return newson
}
let sub2 = createson(parent2,'famle')
console.log(sub2)
sub2.getName()
sub2.getsex()
根据上面的代码可以建立如下的原型链图,如果不对希望有大佬指正下
寄生式继承因为使用了一个函数以某种形式来增强对象,最后返回对象,那么复用率就不高,导致效率低。
寄生组合式继承
了解了组合继承和寄生继承之后就是寄生式组合继承了,它是通过借用构造函数来继承属性,通过原型链形式来继承方法,会解决2次调用父类函数以及复用率的问题。
这里使用《JavaScript高级程序设计》中的代码来解释继承的方法
// 实现继承的核心函数
function inheritPrototype(subType,superType) {
function F() {};
//F()的原型指向的是superType
F.prototype = superType.prototype;
//subType的原型指向的是F()
subType.prototype = new F();
// 重新将构造函数指向自己,修正构造函数
subType.prototype.constructor = subType;
}
// 设置父类
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
SuperType.prototype.sayName = function () {
console.log(this.name)
}
}
// 设置子类
function SubType(name, age) {
//构造函数式继承--子类构造函数中执行父类构造函数
SuperType.call(this, name);
this.age = age;
}
// 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费
inheritPrototype(SubType, SuperType)
// 添加子类私有方法
SubType.prototype.sayAge = function () {
console.log(this.age);
}
var instance = new SubType("Taec",18)
console.dir(instance)
可以看到很好的继承了父类的方法和属性以及自己添加属性和方法,并且只调用了1次父类构造函数,同时保证了原型链的完整,是一种理想的继承方法。下图是自己理解的图示,如果有错误希望大佬来指正
参考了一些文章: