Step-By-Step
Step-By-Step copied to clipboard
寄生组合式继承的基本思想是什么?有哪些优缺点?
寄生组合式继承的基本思想是为了解决组合继承的缺点,组合继承调用了两次父构造函数,生成了两个实例属性,只不过实例上的覆盖了原型上的属性。用了寄生式继承的方法,将子类原型指向父类原型,一般是Object.create() 与 Object.setPrototype() 缺点: 感觉还是父类原型中的引用类型值会被所有下面的实例共享,一个改变,其它都变了,,
显式混入模式的一种变体被称为‘寄生继承’,他即是显式的又是隐式的。
//传统的js类 vehicle
function Vehicle() {
this.engines = 1;
}
Vehicle.prototype.ignition = function () {
console.log('turning on my engine.')
}
Vehicle.prototype.drive = function () {
this.ignition();
console.log('steering and moveing forword.')
}
//寄生类 Car
function Car() {
//首先,car是一个Vehicle
var car = new Vehicle();
//接着我们对car进行定制
car.wheels = 4;
var vehDrive = car.drive;
//重写Vehicle::drive()
car.drive = function () {
vehDrive.call(this);
console.log(`rolling on all ${this.wheels}wheels!`)
}
return car;
}
var myCar = new Car();
myCar.drive();
//turning on my engine.
// steering and moveing forword.
// rolling on all 4wheels!
如你所见,首先我们复制一份vehicle父类的定义,然后混入子类的定义,然后用这个复合对象构建实例。
摘自《你不知道的JavaScript上》
组合继承是JavaScript最常用的继承模式。组合继承最大的问题是,无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。 组合式继承
function SuperType(name){
this.name=name
this.color=["red","blue","green"]
}
SuperType.prototype.sayName=function(){
console.log(this.name)
}
function SubType(name,age){
SuperType.call(this,name)//第二次调用SuperType,又有了实例属性name和color了
this.age=age
}
//第一次调用SuperType,实例属性name和color和SuperType的prototype属性都给了SubType的prototype对象
SubType.prototype=new SuperType()
SubType.prototype.constructor=SubType
SubType.prototype.sayAge=function(){
console.log(this.age)
}
寄生组合式继承
function inheritPrototype(subType,superType){
var prototype=Object.create(superType.prototype)
prototype.constructor=subType
subType.prototype=prototype
}
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)
}
这种方式的高效率体现在它只调用了一次SuperType构造函数,并且因此避免了SubType.prototype上面创建不必要,多余的属性。与此同时原型链还能保持不变还能用instanceof和isPrototypeOf.
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路:
不必为了指定子类型的原型而调用超类型的构造函数,我们需要的仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示:
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType;//增强对象
subType.prototype = prototype;//指定对象
}
- 第一步:创建超类型原型的一个副本
- 第二步:为创建的副本添加
constructor
属性 - 第三步:将新创建的对象赋值给子类型的原型
至此,我们就可以通过调用 inheritPrototype
来替换为子类型原型赋值的语句:
function SuperType(name) {
this.name = name;
this.colors = ['pink', 'blue', 'green'];
}
//...code
function SuberType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SuberType.prototype = new SuperType();
inheritPrototype(SuberType, SuperType);
//...code
优点:
只调用了一次超类构造函数,效率更高。避免在SuberType.prototype
上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。
因此寄生组合继承是引用类型最理性的继承范式。
寄生组合式继承 类似于组合式继承 只不过组合式继承在实现时调用了两次超集 即实例化两次父类型,而寄生组合式继承只需调用一次超集,即利用构造函数继承属性 利用原型式继承方法。
组合式继承实现如下:
function Super(text){
this.text = text
this.like = ['唱','调','rap','篮球']
}
Super.prototype.say=function(){
console.log(this.text)
}
function Suber(text){
Super.call(this,text)
}
Suber.prototype=new Super('cccccccccccc');
console.log(Suber.prototype.constructor); // Super
Suber.prototype.constructor= Suber; // Suber
Suber.prototype.say();
// var sub1 = new Suber();
// sub1.like.push('小姐姐')
// console.log(sub1.like);
// var sub2 = new Suber2();
// console.log(sub2.like);
寄生组合式继承实现如下:
function clonePrototype(Super,Suber){
var prototype = Object.create(Super.prototype);
prototype.constructor = Suber;
Suber.prototype = prototype;
}
function Super(name){
this.name = name
this.like = ['sing','dance','rap','basketball']
}
Super.prototype.sayName=function(){
console.log(this.name)
}
function Suber(name,age){
Super.call(this,name) // 继承属性
this.age=age
}
clonePrototype(Super,Suber);
Suber.prototype.sayAge=function(){
console.log(this.age)
}
var sub1 = new Suber('sss',45);
console.log(sub1.name);
sub1.sayName();
sub1.sayAge();
为什么要贴上面的三张图?
其实最下面的那张图可以帮助理解 new 操作符到底干了啥?
1.创建了一个空对象。 2.将空对象的__proto__属性=要实例化对象的prototype。 3.为此对象添加属性 name age like等 只针对例子。 4.返回此对象。
https://github.com/ziyi2/js/blob/master/JS%E7%B1%BB%E5%92%8C%E7%BB%A7%E6%89%BF.md
包含ES5和ES6对于类的继承的不同
寄生组合继承
function CreateDog(obj) {
function Dog () {
}
Dog.prototype = obj
return new Dog()
}
function Animal () {
this.type = ['aniaml']
}
Animal.prototype.sayType = function () {
console.log(this.type)
}
function Wolve () {
Animal.call(this)
this.hitType = 'hit'
}
function Addextend(wolve, animal) {
const prototype = CreateDog(animal.prototype)
prototype.constructor = wolve
wolve.prototype = prototype
wolve.prototype.sayHittype = function () {
console.log(this.hitType)
}
}
Addextend(Wolve, Animal)
const wolve = new Wolve()
// const wolve2 = new Wolve()
wolve.sayType()
wolve.sayHittype()
如名字所示,就是组合和寄生的结合:
- 相比寄生,他继承的数据属性不会互相影响
- 相比组合又少了一次Animal 的调用
- 基本思想:和组合继承有点类似,不过它解决组合继承调用两次父类的构造函数,就是在子类的原型调用父类的构造函数时做下改变,用寄生式继承来做这步操作,我们想要无非不就是父类原型的一个副本而已
- 优点: 解决了组合继承两次调用父类的构造函数,普遍人员认为这是最理想的一种方式
function inheritPrototype(child,parent){
var prototype = Object(parent.prototype); // 创建对象
prototype.constructor = child; // 增强对像
child.prototype = prototype; // 指定对象
}
function Animal(speices){
this.speices = speices;
this.skills = ["jump","climb","catch","run"];
}
Animal.prototype.getSpeices = function(){
console.log(this.speices)
}
function Dog(species,color){
Animal.call(this,species);
this.color = color;
}
inheritPrototype(Dog,Animal);
// 在组合继承里面,这句是 Dog.prototype = new Animal()
var dog1 = new Dog('牧羊犬','black');
dog1.getSpeices(); // 牧羊犬
寄生组合式继承的基本思想是为了解决组合继承的缺点,组合继承调用了两次父构造函数,生成了两个实例属性,只不过实例上的覆盖了原型上的属性。用了寄生式继承的方法,将子类原型指向父类原型,一般是Object.create() 与 Object.setPrototype() 缺点: 感觉还是父类原型中的引用类型值会被所有下面的实例共享,一个改变,其它都变了,,
这位兄台,对于 “父类原型中的引用类型值会被所有下面的实例共享” 这个缺点,你可以在父类原型上定义一个函数 return 出一个对象就可以了吧,这样每次修改子类实例中继承来子父类原型共享属性都不会其他子实例的修改而变化了
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路:
不必为了指定子类型的原型而调用超类型的构造函数,我们需要的仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示:
function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); //创建对象 prototype.constructor = subType;//增强对象 subType.prototype = prototype;//指定对象 }
- 第一步:创建超类型原型的一个副本
- 第二步:为创建的副本添加
constructor
属性- 第三步:将新创建的对象赋值给子类型的原型
至此,我们就可以通过调用
inheritPrototype
来替换为子类型原型赋值的语句:function SuperType(name) { this.name = name; this.colors = ['pink', 'blue', 'green']; } //...code function SuberType(name, age) { SuperType.call(this, name); this.age = age; } SuberType.prototype = new SuperType(); inheritPrototype(SuberType, SuperType); //...code
优点:
只调用了一次超类构造函数,效率更高。避免在
SuberType.prototype
上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。因此寄生组合继承是引用类型最理性的继承范式。
写错了点吧。最后那应该不需要再new 一次父类了。
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路:
不必为了指定子类型的原型而调用超类型的构造函数,我们需要的仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示:
function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); //创建对象 prototype.constructor = subType;//增强对象 subType.prototype = prototype;//指定对象 }
- 第一步:创建超类型原型的一个副本
- 第二步:为创建的副本添加
constructor
属性- 第三步:将新创建的对象赋值给子类型的原型
至此,我们就可以通过调用
inheritPrototype
来替换为子类型原型赋值的语句:function SuperType(name) { this.name = name; this.colors = ['pink', 'blue', 'green']; } //...code function SuberType(name, age) { SuperType.call(this, name); this.age = age; } SuberType.prototype = new SuperType(); inheritPrototype(SuberType, SuperType); //...code
优点:
只调用了一次超类构造函数,效率更高。避免在
SuberType.prototype
上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。因此寄生组合继承是引用类型最理性的继承范式。
是不是写错了,为啥还需要调用inheritPrototype
前还需要
SuberType.prototype = new SuperType();