前文说过,组合继承是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. CodeForces-721A-One-dimensional Japanese Crossword

    链接: https://vjudge.net/problem/CodeForces-721A 题意: Recently Adaltik discovered japanese crosswords. ...

  2. Linux基础教程 linux下cat 命令使用详解

    cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 1.命令格式: cat [选项] [文件] ...

  3. 【深入理解CLR】1:CLR的执行模型

    将源代码编译成托管模块 下图展示了编译源代码文件的过程.如图所示,可用支持 CLR 的任何一种语言创建源代码文件.然后,用一个对应的编译器检查语法和分析源代码.无论选用哪一个编译器,结果都是一个托管模 ...

  4. 【spoj2774】最长公共子串

    题目描述: 给你两个字符串,求它们最长公共子串的长度,如果不存在公共子串则输出0. 样例输入: yeshowmuchiloveyoumydearmotherreallyicannotbelieveit ...

  5. tf_upgrade_v2.exe实验

    实验前 import tensorflow as tf import numpy as np #create data x_data=np.random.rand(100).astype(np.flo ...

  6. Codechef TRIPS Children Trips (分块、倍增)

    题目链接: https://www.codechef.com/problems/TRIPS 感觉CC有点毒瘤啊.. 题解: 首先有一个性质可能是因为太傻所以网上没人解释,然而我看了半天: 就是正序和倒 ...

  7. jvisualvm性能监控

    一.配置JMX 1.进入tomcat bin目录 vim catalina.sh #!/bin/sh下面加入: #!/bin/sh JAVA_OPTS="-Dcom.sun.manageme ...

  8. sqli-labs(22)

    接下里我们进入第二二关 好像和第21关一样 cookie的base64加密注入 闭合变成了双引号而已 0X01 构造语句进行尝试 " union select 1,2,3# IiB1bmlv ...

  9. 《第40天 : JQuery - 手风琴列表》

    源码下载地址:链接:https://pan.baidu.com/s/1x9c1... 提取码:2bzr 如果有赞就很幸福了. 今天要和你们分享的是我看了JQuery库的手风琴列表样式.它的核心在于它的 ...

  10. LeetCode_509.斐波那契数

    LeetCode-cn_509 509.斐波那契数 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列.该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) ...