JavaScript中的继承之寄生组合式继承

先说说组合继承。最常用的继承方式组合继承,其最大的问题是无论在什么情况下,都会调用两次超类型的构造函数:一次是在创建子类原型的时候,另一次是在子类型构造函数内部。

组合继承是通过原型继承方法和原型属性,构造函数继承实例属性。但子类通过原型也继承了超类型的全部实例属性(方法暂且不说),即超类的实例属性成为子类的原型属性,所以不得不在调用子类构造函数时重写这些属性。也就是说在子类的原型对象上继承来自超类的实例属性完全是多余的。

看一个组合继承的例子。

function SuperType(name){
    this.name = name;
    this.colors = [‘red‘,‘blue‘,‘green‘];
}

SuperType.prototype.sayName = function(){
    alert(this.name);
}

function SubType(name,age){
    SuperType.call(this,name);             //第二次调用SuperType()
    this.age = age;
}

SubType.prototype = new SuperType();      //第一次调用SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge=function(){
     alert(this.age);
};

var instance = new SubType(‘Greg‘,39);     //调用SubType构造函数,重写原型属性instance.colors.push(‘black‘);      //重写原型属性

  在第一次调用SuperType构造函数时,SubType.prototype得到两个属性,name和colors(这两个通过原型继承来的属性是多余的)。当创建instance实例调用SubType的构造函数时会再一次调用SuperType的构造函数,这一次又在新对象上创建了实例属性name和colors,也就是重写了原型对象的属性,屏蔽了原型中两个同名属性。

为了避免这种两次调用超类构造函数导致子类原型对象创建了多余属性的缺陷,可以使用寄生组合式继承。

什么是寄生组合式继承?即通过借用构造函数来继承属性,通过原型链的混成方式来继承方法。

基本思路是:不必为了指定子类型的原型而调用构造函数,我们所需要的无非是超类型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后将结果指定给子类型的原型。

基本模式如下:

还是要用之前的 object函数。

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

  接着是寄生组合式继承的基本模式。

function inheritPrototype(subType,superType){
    var prototype = object(superType.prototype);    //创建对象
    prototype.constructor = subType;    //增强对象
    subType.prototype = prototype;    //指定对象
}

  此函数接收两个参数,子类构造函数和超类构造函数。函数内部,第一步创建超类原型对象的一个副本,第二步为副本添加constructor属性,使其指向subType,弥补因为重写原型而失去默认的constructor属性。最后一步,将副本赋值给子类型的原型。整个过程说的简单点,就是将超类原型对象的一个副本复制给子类的原型对象。这样一来就可以避免继承超类的实例属性,也就是避免了在子类原型对象上创建多余的属性了。再举一个例子。

function superType(name){
    this.name = namel
    this.colors = [‘red‘,‘blue‘,‘yellow‘];
}

superType.prototype.sayName = function(){
    alert(this.name);
}

function subType(name, age){
    superType.call(this,name);     //通过构造函数继承实例属性
    this.age = age;
}

inheritPrototype(subType,superType);    //仅调用一次超类构造函数

subtype.prototype.sayAge = function(){
    alert(this.age);
}

  这个例子的高效率体现在它只调用了一次superType构造函数,并且避免了在subType.prototype上创建不必要的属性。与此同时,原型链还能保持不变,因此可以正常使用instanceof()和isPrototypeOf()。寄生式组合继承是引用类型最理想的继承范式。

时间: 2024-12-28 00:37:48

JavaScript中的继承之寄生组合式继承的相关文章

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

说好的讲解JavaScript继承,可是迟迟到现在讲解.废话不多说,直接进入正题. 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考<面向对象JS基础讲解,工厂模式.构造函数模式.原型模式.混合模式.动态原型模式>,接下来讲一般通过那些方法完成JavaScript的继承. 原型链 JavaScript中实现继承最简单的方式就是使用原型链,将子类型的原型指向父类型的实例即可,即“子类型.prototype = new 父类型();”,实现方法如下

JavaScript之原型式继承&amp;寄生式继承和寄生组合式继承以及优缺点

一.原型式继承 1.这种方法并没有使用严格意义上的构造函数,借助原型可以基于已有的对象创建新的对象 function object(o) { function F() {} F.prototype = o; return new F(); } // 在object()函数内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数原型,最后返回了这个临时类型的一个新实例. // object()本质上对其中传入的对象进行了一次浅复制 // 看如下的例子: var person = { na

组合继承 和 原型式继承、寄生组合式继承

//以下代码均摘自 Nicholas C.Zakas<Professional JavaScript for Web Developers> //组合继承实例代码: function SuperType(name) {     this.name = name;     this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() 

组合继承与寄生组合式继承

组合继承 将原型链和借用构造函数的技术组合到一块. 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承. 超类的属性被继承了两次,一次是在子类的构造函数中,使得子类实例拥有各自的属性:一次是在子类的原型中,使得子类拥有相同的属性. 1 function SuperType(name){ 2 this.name = name; 3 this.colors = ["red","blue","green"]; 4 } 5 S

javascript寄生组合式继承

下面是javascript寄生组合式继承源代码,选自这里.讲解请见我所加注释: function creatObject(o){//该函数是为了创建原型链对象所用,传入值o为一个function F(){}//新建函数 F.prototype = o;//设置该函数的原型属性为传入对象 return new F();//调用该函数后返回链式对象F.prototype=o; } function inheritPrototype(subType, superType){//用于设置对象属性 var

JavaScript寄生组合式继承分析

JavaScript寄生组合式继承特点: 避免了在子类prototype上创建不必要多余的属性,相比直接继承基类的实例效率要高. 是JavaScript 实现继承的最有效方式. <script> //定义基类构造函数和属性 function BaseClass(name,age){ this.name=name; this.age=age; } //在基类原型上添加sayName方法 BaseClass.prototype.sayName=function(){ console.log(thi

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

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

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

组合式继承:将类式继承同构造函数继承组合使用,但是存在一个问题,子类不是父类的实例,而子类的原型式父类的实例,所以才有了寄生组合式继承. 意思就是说,寄生就是寄生式继承,寄生式继承就是依托于原型继承,原型继承又与类式继承差不多,所以另外一种继承模式应该是构造函数继承.当然子类不是父类的实例的问题是由于类式继承引起的. 说道这,我不得不说一下,道格拉斯大哥对寄生式继承的改造 function inheritPrototype(subClass,superClass){ //复制一份父类的原型副本保

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

在之前javascript面向对象系列的文章里面,我们已经探讨了组合继承和寄生继承,回顾下组合继承: 1 function Person( uName ){ 2 this.skills = [ 'php', 'javascript' ]; 3 this.userName = uName; 4 } 5 Person.prototype.showUserName = function(){ 6 return this.userName; 7 } 8 function Teacher ( uName