前文说过,组合继承是javascript最常用的继承模式,不过,它也有自己的不足:组合继承无论在什么情况下,都会调用两次父类构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数内部.子类最终会包含父类对象的全部实例属性,但我们不得不在调用子类构造函数时重写这些属性.请再看一次组合继承的例子:

function SuperType(name){
this.name=name;
this.friends=["gay1","gay2"];
}
SuperType.prototype.sayName=function(){
alert(this.name);
};
funciton SubType(name,age){
SuperType.call(this,name); //第二次调用SuperType();
this.age=age;
}
SubType.prototype=new SuperType(); //第一次调用SuperType()
SubType.prototype.sayAge=function(){
alert(this.age);
};

  在第一次调用SuperType构造函数时,SubType.prototype会得到两个属性:name和friends,他们都是SuperType的实例属性.只不过现在位于SubType的原型中.当调用SubType构造函数时,又会调用一次SuperType构造函数,这一次又在新对象上创建了实例属性name和friends.于是,这两个属性就屏蔽了原型中的两个同名属性.

  结果是,有两组name和friends属性,一组在SubType的实例上,一组在SubType的原型上.这就是调用两次SuperType构造函数的结果.而现在,找到了解决这个问题的方法:寄生组合式继承.

  寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法.思路:不必为了指定子类的原型而调用父类的构造函数,我们所需要的无非就是父类原型的一个副本而已.本质上,就是使用寄生式继承来继承父类的原型,然后在将结果指定给子类的原型:

function inheritPrototype(subType,superType){
var prototype=object(superType.prototype); //创建父类原型的一个副本 等同于使用Object.create(superType.prototype)
prototype.constructor=subType; //为副本添加constructor属性,弥补重写原型而失去的constructor属性
subType.prototype=prototype; //将创建的对象(副本)赋值给子类的原型
}

  这样,我们就可以通过调用inheritPrototype()函数,替换前面例子中为子类原型的赋值语句了:

function inheritPrototype(subType,superType){
var prototype=Object.create(superType.prototype); //创建父类原型的一个副本 等同于使用Object.create(superType.prototype)
prototype.constructor=subType; //为副本添加constructor属性,弥补重写原型而失去的constructor属性
subType.prototype=prototype; //将创建的对象(副本)赋值给子类的原型
}
function SuperType(name){
this.name=name;
this.friends=["gay1","gay2"];
}
SuperType.prototype.sayName=function(){
alert(this.name);
};
function SubType(name,age){
SuperType.call(this,name); //继承SuperType
this.age=age; //扩展出age属性
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge=function(){
alert(this.age);
};//扩展出sayAge方法 var person1=new SubType("nUll",25);
var person2=new SubType("mywei",25);
person1.friends.push("gay3");
person1.sayName();
person1.sayAge();
alert(person1.friends); //gay1,gay2,gay3
alert(person2.friends); //gay1,gay2
alert(person1 instanceof SubType); //true
alert(person1 instanceof SuperType); //true
alert(SubType.prototype.isPrototypeOf(person1)); //true
alert(SuperType.prototype.isPrototypeOf(person1)); //true

  这个例子的高效率体现在它只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上创建不必要的 多余的属性.与此同时,原型链还能保持不变.因此,还能够正常使用instanceof 和isPrototypeOf确定继承关系.

YUI的YAHOO.lang.extend()方法采用了寄生组合式继承。

javascript中的继承-寄生组合式继承的更多相关文章

  1. JavaScript高级程序设计之寄生组合式继承

    在继承中常会出现两个问题: 父类的属性变成了子类的原型 构造器指向混乱 寄生组合式继承解决了这样的问题: 属性继承到属性 原型继承到原型 构造器指向明确 // 父类 var Super = funct ...

  2. JavaScript对寄生组合式继承的理解

    有关JavaScript的几种继承方式请移步JavaScript的几种继承方式 原型链的缺陷 SubType.prototype = new SuperType(); 这样做的话,SuperType构 ...

  3. JavaScript寄生组合式继承分析

    JavaScript寄生组合式继承特点: 避免了在子类prototype上创建不必要多余的属性,相比直接继承基类的实例效率要高. 是JavaScript 实现继承的最有效方式. <script& ...

  4. JavaScript继承基础讲解,原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承

    说好的讲解JavaScript继承,可是迟迟到现在讲解.废话不多说,直接进入正题. 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考<面向对象J ...

  5. 详解js中的寄生组合式继承

    寄生组合式继承是js中最理想的继承方式, 最大限度的节省了内存空间. js中的寄生组合式继承要求是: 1.子对象有父对象属性的副本, 且这些不应该保存在子对象的prototype上.       2. ...

  6. javaScript设计模式之面向对象编程(object-oriented programming,OOP)--寄生组合式继承

    组合式继承:将类式继承同构造函数继承组合使用,但是存在一个问题,子类不是父类的实例,而子类的原型式父类的实例,所以才有了寄生组合式继承. 意思就是说,寄生就是寄生式继承,寄生式继承就是依托于原型继承, ...

  7. Javascript继承6:终极继承者----寄生组合式继承

    /* * 寄生式继承依托于原型继承,原型继承又与类式继承想象. * 即: 原型与构造函数的组合继承 * 寄生式继承 继承原型 * 传递参数 childClass 子类 * 传递参数 parentCla ...

  8. js组合继承和寄生组合式继承比较

    本文是原创文章,如需转载,请注明文章出处 1.js中实现组合继承(B继承A): function A(name){ this.name = name; this.ary = ["AA&quo ...

  9. [js高手之路]寄生组合式继承的优势

    在之前javascript面向对象系列的文章里面,我们已经探讨了组合继承和寄生继承,回顾下组合继承: function Person( uName ){ this.skills = [ 'php', ...

随机推荐

  1. HDU-3605-Escape(最大流, 状态压缩)

    链接: https://vjudge.net/problem/HDU-3605 题意: 2012 If this is the end of the world how to do? I do not ...

  2. day02 计算机基础部分作业题

    1. 简述执行Python程序的两种方式以及他们的优缺点: 交互式: 优点:在cmd窗口环境下,运行Python解释器,执行一行代码打印一行,执行速度快,立马显示结果: 缺点:关闭窗口,被执行的代码和 ...

  3. JAVA笔记17-容器之一 图、Collection接口、Iterator接口(重要)

    掌握1136: (1)1个图 (2)1个类:Collections (3)3个知识点:For(了解),Generic泛型,Auto-boxing/unboxing(自动打包/解包) (4)6个接口:C ...

  4. int 和guid做主键的时候性能的区别

    1.在经常需要做数据迁移的系统中,建议用Guid.并且在相应的外键字段,也就是用来做连接查询的字段添加非聚集索引,对于改善性能有极大的好处.where条件的字段也可以适当添加非聚集索引. 2.在使用G ...

  5. python调用Opencv库和dlib库

    python是一门胶水语言,可以调用C++编译好的dll库 python调用opencv-imggui.dll文件 https://www.cnblogs.com/zhangxian/articles ...

  6. Windows10 + VS2015 (Win SDK10)环境下的64位 VTK编译小结

    之前在学习vtk过程中,感觉vtk的编译还是很简单的,基本上不会碰到什么棘手的错误.但是,当我在Win10+VS2015这个环境下配置时,却遇到了麻烦.经过一番折腾之后,终于将vtkbian编译成功了 ...

  7. HDU3465--Life is a Line(树状数组求逆序数,离散化)

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submission(s ...

  8. (四)mysql -- 常用函数

    今天get一个,先记录一下 以后慢慢补充~ 将varchar转换成int 例如:select * from tb_1 order by cast(sport_sum as unsigned integ ...

  9. 关于tomcat的server.xml里host节点配置的一些说明

    其实对这个一直搞不清楚,后来公司的网站遭遇与IIS进行整合,然后上面有几个应用需要进行配置,所以对tomcat的server.xml进行了一些深入的了解 Host的节点主要是起一个对域名解析到那个虚拟 ...

  10. 【Python】学习笔记七:函数

    函数的目的:重复使用相同的一段程序 函数的定义 下面是我自定义的一个求a,b,c三个参数平方和的函数 #a,b,c三个参数的平方和 def pow_sum(a,b,c): x = pow(a,2)+p ...