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

  1. function SuperType(name){
  2. this.name=name;
  3. this.friends=["gay1","gay2"];
  4. }
  5. SuperType.prototype.sayName=function(){
  6. alert(this.name);
  7. };
  8. funciton SubType(name,age){
  9. SuperType.call(this,name); //第二次调用SuperType();
  10. this.age=age;
  11. }
  12. SubType.prototype=new SuperType(); //第一次调用SuperType()
  13. SubType.prototype.sayAge=function(){
  14. alert(this.age);
  15. };

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

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

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

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

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

  1. function inheritPrototype(subType,superType){
  2. var prototype=Object.create(superType.prototype); //创建父类原型的一个副本 等同于使用Object.create(superType.prototype)
  3. prototype.constructor=subType; //为副本添加constructor属性,弥补重写原型而失去的constructor属性
  4. subType.prototype=prototype; //将创建的对象(副本)赋值给子类的原型
  5. }
  6. function SuperType(name){
  7. this.name=name;
  8. this.friends=["gay1","gay2"];
  9. }
  10. SuperType.prototype.sayName=function(){
  11. alert(this.name);
  12. };
  13. function SubType(name,age){
  14. SuperType.call(this,name); //继承SuperType
  15. this.age=age; //扩展出age属性
  16. }
  17. inheritPrototype(SubType,SuperType);
  18. SubType.prototype.sayAge=function(){
  19. alert(this.age);
  20. };//扩展出sayAge方法
  21.  
  22. var person1=new SubType("nUll",25);
  23. var person2=new SubType("mywei",25);
  24. person1.friends.push("gay3");
  25. person1.sayName();
  26. person1.sayAge();
  27. alert(person1.friends); //gay1,gay2,gay3
  28. alert(person2.friends); //gay1,gay2
  29. alert(person1 instanceof SubType); //true
  30. alert(person1 instanceof SuperType); //true
  31. alert(SubType.prototype.isPrototypeOf(person1)); //true
  32. 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. windows补丁服务器

    一.WSUS 安装要求 1.硬件要求: 对于多达 13000 个客户端的服务器,建议使用以下硬件:* 4 Core E5-2609 2.1GHz 的处理器* 8 GB 的 RAM 2.软件要求: 要使 ...

  2. DevOps之持续集成Pipeline(一)

    一.Pipeline介绍     Jenkins2.0中最大的一个特性就是Pipeline,实际使用中Pipeline已经超越了我们对jenkins本身的理解,可能在之前我们大多数把Jenkins当做 ...

  3. udp拼接传递数据包

    1.拼接项少 pl = ["<0112>","<32>","<1024x768>","< ...

  4. 观察者模式------《Head First 设计模式》

    第二章---观察者模式 xzmxddx 学习方式:书籍<Head First 设计模式>,这本书通俗易懂,所有知识点全部取自本书. 面向对象设计原则 封装变化 多用组合,少用继承 针对接口 ...

  5. Charles模拟数据

    安装好Charles 桌面创建json文件

  6. sh_09_打印多条分隔线

    sh_09_打印多条分隔线 def print_line(char, times): """打印单行分隔线 :param char: 分隔字符 :param times: ...

  7. (C#- 多线程) 在线程中创建object,共享问题。

    研究如下问题: 1. 在一个进程的主线程中创建一个Object,其他线程都可以访问这个Object,并操作Object的方法. - 多线程同步问题. 2. 在一个进程的多个线程里面,每个线程都创建同一 ...

  8. Python os模块方法

    os模块提供了大量有用的方法来处理文件和目录.本章节中的代码实例是在 Ubuntu Linux系统上运行来演示. 大多数有用的方法都列在这里 - 编号 方法 描述/说明 1 os.access(pat ...

  9. androi自定义自动换行的View(类似网页的标签Tag)

    看来只有礼拜天才有时间写点博客啊,平时只能埋头苦干了.今天在公司加班,遇到一个需求,就是自动换行的TextView,有点像网页的tag标签,点击一下,就自动加上去了,不过这个是根据后台拿来的数据来显示 ...

  10. sun.misc.BASE64Decoder 替代

    加密解密经常用到sun.misc.BASE64Decoder处理,编译时会提示: sun.misc.BASE64Decoder是内部专用 API, 可能会在未来发行版中删除 解决办法: Java8以后 ...