javascript继承

来源:互联网 发布:淘宝联盟官方发单助手 编辑:程序博客网 时间:2024/04/28 14:46

之前看《javascript高级程序设计》的几种继承实现的方式,每过一段时间就会忘记这几种方式,所以写下此文。

继承实现有以下几种方式:

1、原型链

使用原型链作为实现继承,其思想是通过对象可以访问其原型链上的属性和方法。

实现方法:

让原型对象等于另一个类型的实例。

代码如下:

function SuperType(){this.property = true;}SuperType.prototype.getSuperValue = function(){return this.property;};function SubType(){this.subproperty = false;}//继承了SuperTypeSubType.prototype = new SuperType();SuperType.prototype.getSubValue = function(){return this.subproperty;};var instance = new SubType();alert(instance.getSuperValue()); //true

这个例子中的实例以及构造函数和原型之间的关系,如图:


上述代码,并没使用SubType默认提供的原型,是使用了SuperType的实例作为原型。因此,这个原型不仅拥有SuperType的实例上的全部属性和方法,而且其内部

还有一个指针,指向SuperType的原型。具体过程是这样的:instance指向SubType的原型,SubType的原型又指向SuperType的原型。getSuperValue()

方法仍然还在SuperType.prototype中,而property则位于SubType.prototype中,这是因为property是一个实例属性,而getSuperValue()则是一个原型方法。

既然SubType.prototype现在是SuperType实例,那么property当然就位于该实例中。

注意:a)instance.constructor现在指向的是SuperType,这是因为SubType.prototype中的constructor被重写了。

    b)  通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做就会重写原型链。


这种方式的缺点:

a) 包含引用类型值的原型属性会被所有实例共享

b) 在创建子类型的实例时,无法向父级的构造函数中传递参数


2、借用构造函数

这种技术的思想是在子类构造函数的内部调用父级的构造函数。通过使用apply或call方法可以在新创建的对象执行构造函数。

function SuperType(){this.colors = ["red", "blue", "green"];}function SubType(){//继承了SuperTypeSuperType.call(this);}var instance1 = new SubType();instance1.colors.push("black");alert(instance1.colors);   //"red,blue,green,black"var instance2 = new SubType();alert(instance2.colors);  //"red,blue,green"

注意:为了避免父级构造函数重写子类型的属性,应该在调用父级构造函数后,再添加子类型中定义的属性。

这种方式优点是:可以在子类构造函数中向父类构造函数传递参数,解决了原型链继承的问题。

缺点是:无法避免构造函数模式存在的问题(方法都必须在构造函数中定义),因此失去了复用性。


3、组合继承

 也叫伪经典继承,它将原型链和借用构造函数的技术组合到一块。其背后的思想是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

<script type="text/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);this.age = age;}//继承方法SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function(){alert(this.age);};var instance1 = new SubType("Nsicholas", 29);instance1.colors.push('black');alert(instance1.colors);   //"red,blue,green,black"instance1.sayName();       //"Nicholas"instance1.sayAge();    //29var instance2 = new SubType("Greg", 27);alert(instance2.colors);    //"red,blue,green"instance2.sayName();        //"Greg"instance2.sayAge();         //27
组合继承避免了原型链和借用构造函数的缺陷,融合它们的优点,称为JavaScript中最常用的继承模式。而且,instanceof和isPrototypeOf()也能够用于识别基于组合继承创建的对象。

组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数:一次在创建子类原型的时候,另一次是在子类构造函数内部。子类最终会包含超类型对象的全部实例属性,但我们不得不在调用子类型构造函数时,重写这些属性。

代码演示:

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);};
上面代码,在第一次调用SuperType构造函数时,SubType.prototype会得到两个属性:name和colors.他们都是SuperType的实例属性,只不过是位于SubType

的原型上。当调用SubType构造函数时,又会调用一次SuperType构造函数,这一次又在新对象上创建了实例属性name 和colors。而这两个属性就屏蔽了原型中的两个同名属性。


4、原型式继承

这种继承的思路是:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

通过下面这个函数可以达到目的。

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

这个函数的工作是,先创建了一个临时的构造函数,然后把它的原型设置为所传人的对象,最后返回这个临时构造函数的新实例。从本质上说,该函数对传人的对象

进行了一次浅拷贝。

请看下面使用的例子:

function object(o){function F(){}F.prototype = o;return new F();}var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = object(person);anotherPerson.name = "Greg";anotherPerson.friends.push('Rob');var yetAnotherPerson = object(person);yetAnotherPerson.name = "Linda";yetAnotherPerson.friends.push("Barbie");alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
注意:以这种方式指定的任何属性都会覆盖原型对象上的同名属性。

这种方式的优点:就是不用那么兴师动众地创建构造函数,在只想让一个对象与另一个对象保存类似的情况下可以使用。

缺点:它和原型链模式一样,当包含引用类型值的属性时,都会共享该属性值。


5、寄生式继承

寄生式(parasitic)继承是与原型式继承紧密相关的一种思路。寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后像真的是它做了所有工作一样返回对象。

代码演示:

function object(o){function F(){}F.prototype = o;return new F();}
function createAnother(original){var clone = object(original); //调用函数创建一个新clone.sayHi = function(){   //以某种方式来增强这个对象alert("hi");};return clone;  //返回这个对象}
var person = {name:'Nicholas',friends: ["Shelby", "Court", "Van"]};var anotherPerson = createAnother(person);anotherPerson.sayHi(); // "hi"

这个例子基于person返回一个新对象anotherPerson.新对象不仅具有person的所有属性和方法,而且还有自己的sayHi()方法。

当对象对象不是自定义类型和构造函数的的情况下,寄生式继承也是一种有用的模式。任何能返回新对象的函数都适用于此模式。

缺点:

与借用构造函数一样,做不到函数的复用。


6、寄生组合式继承

组合继承出现两次调用父类构造函数,为了解决这个问题,产生了寄生组合式继承。它是通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其思想是:

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

寄生组合式实现:

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属性,从而修正了constructor属性。最后一步,将新创建的对象赋值给子类的原型。

寄生组合式应用示例:

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; //指定对象}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);this.age = age;}inheritPrototype(SubType, SuperType);SubType.prototype.sayAge = function(){alert(this.age);};

寄生组合式继承只调用了一次SuperType构造函数,并且避免了在SubType.prototype上创建不必要的、多余的属性。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。YUI的YAHOO.lang.extend()采用了这个模式。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 亚马逊海外购超过两万的额度怎么办 增值税申报表进项税转出忘填怎么办 一般纳税人注册下来后未营业怎么办 增值税税率把3错开成了5怎么办 在义乌做压痕加工老板拖欠钱怎么办 蓝洞棋牌是赌博输了几万怎么办 夏季来月经用卫生巾外阴瘙痒怎么办 用洗衣机洗衣服忘掏卫生纸了怎么办 剖腹产后一个月了还有血怎么办 剖腹产两个月同房后下面有血怎么办 剖腹产后月子里便秘有血怎么办 产后10天b超检查有血块怎么办 吃完优思明月经没有血块怎么办 刨腹产妇42天还有恶露怎么办 打完孩子第五天同房了出血了怎么办 打完孩子同房了出了一点血怎么办 宫腔镜检查一个月同房流血多怎么办 宫颈活检后三天同房有出血怎么办 顺产侧切两个月之后同房感染怎么办 顺产40天还有暗红色的恶露怎么办 来姨妈了没带卫生棉条去游泳怎么办 母猪肚子里面的小猪下不出来怎么办 刚生小猪的母猪肚子胀怎么办 吃了两天中药肚子还疼怎么办 怀孕期间垫了脚够东西怎么办 月经期垫卫生巾有边红肿有疹怎么办 四十天拉今天恶露特别多怎么办 顺产侧切出院几天后伤口裂开怎么办 产后十几撕裂用卫生巾疼怎么办 婴儿绑肚脐的棉黏在肚脐上怎么办 割完双眼皮第五天了很痒怎么办 自体脂肪丰胸做完半年有团块怎么办 假体隆胸一个月了躺着睡很硬怎么办 假体隆胸半月俩胸大小不一样怎么办 假体隆胸拆线后还是起不来床怎么办 假体隆胸术后6天 天天胀痛怎么办 阴部大腿根长了个疙瘩有点痛怎么办 加盟费交了总部不做事怎么办 仓鼠从桌子摔下来后走路别扭怎么办 习惯了一个人天天找你聊天怎么办 来完月经外阴湿疹就严重怎么办