Comments (11)
寄生组合式继承的基本**是为了解决组合继承的缺点,组合继承调用了两次父构造函数,生成了两个实例属性,只不过实例上的覆盖了原型上的属性。用了寄生式继承的方法,将子类原型指向父类原型,一般是Object.create() 与 Object.setPrototype()
缺点: 感觉还是父类原型中的引用类型值会被所有下面的实例共享,一个改变,其它都变了,,
from step-by-step.
显式混入模式的一种变体被称为‘寄生继承’,他即是显式的又是隐式的。
//传统的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上》
from step-by-step.
组合继承是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.
from step-by-step.
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路:
不必为了指定子类型的原型而调用超类型的构造函数,我们需要的仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示:
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
上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。
因此寄生组合继承是引用类型最理性的继承范式。
from step-by-step.
寄生组合式继承 类似于组合式继承 只不过组合式继承在实现时调用了两次超集 即实例化两次父类型,而寄生组合式继承只需调用一次超集,即利用构造函数继承属性 利用原型式继承方法。
组合式继承实现如下:
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.返回此对象。
from step-by-step.
https://github.com/ziyi2/js/blob/master/JS%E7%B1%BB%E5%92%8C%E7%BB%A7%E6%89%BF.md
包含ES5和ES6对于类的继承的不同
from step-by-step.
寄生组合继承
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 的调用
from step-by-step.
- 基本**:和组合继承有点类似,不过它解决组合继承调用两次父类的构造函数,就是在子类的原型调用父类的构造函数时做下改变,用寄生式继承来做这步操作,我们想要无非不就是父类原型的一个副本而已
- 优点: 解决了组合继承两次调用父类的构造函数,普遍人员认为这是最理想的一种方式
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(); // 牧羊犬
from step-by-step.
寄生组合式继承的基本**是为了解决组合继承的缺点,组合继承调用了两次父构造函数,生成了两个实例属性,只不过实例上的覆盖了原型上的属性。用了寄生式继承的方法,将子类原型指向父类原型,一般是Object.create() 与 Object.setPrototype()
缺点: 感觉还是父类原型中的引用类型值会被所有下面的实例共享,一个改变,其它都变了,,
这位兄台,对于 “父类原型中的引用类型值会被所有下面的实例共享” 这个缺点,你可以在父类原型上定义一个函数 return 出一个对象就可以了吧,这样每次修改子类实例中继承来子父类原型共享属性都不会其他子实例的修改而变化了
from step-by-step.
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路:
不必为了指定子类型的原型而调用超类型的构造函数,我们需要的仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示:
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 一次父类了。
from step-by-step.
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路:
不必为了指定子类型的原型而调用超类型的构造函数,我们需要的仅是超类型原型的一个副本,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示:
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();
from step-by-step.
Related Issues (20)
- 实现一个 JSON.stringify HOT 9
- 实现一个 JSON.parse HOT 9
- 实现一个观察者模式 HOT 10
- 使用CSS让一个元素水平垂直居中 HOT 11
- ES6模块和CommonJS模块有哪些差异? HOT 8
- 如何使用Proxy实现简单MVVM HOT 2
- 以下代码的输出的结果为: HOT 7
- 列举常见的JS和CSS兼容性问题
- 介绍下 Set、Map、WeakSet 和 WeakMap 的区别? HOT 1
- Vue组件间是怎么进行参数传递的? HOT 4
- 如果浏览器主线程一直被占据,那么setTimeout会什么时候执行
- rem、em、vh、vw 有什么区别
- flex-grow 与 flex-shrink 的计算规则
- while循环卡死和微任务卡死有什么区别
- sourcemap原理是什么
- 闭包会导致内存泄漏为什么还要使用?
- 前端怎么显示1G的图片甚至1T的图片
- 手写lodash的get方法
- setTimeout回调和fetch回调哪个先执行
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from step-by-step.