javascript继承学习系列之五:其他方式

      除前文学习的三种继承外,还有另外三种继承模式:原型继承(Prototypal Inheritance)、寄生继承(Parasitic Inheritance)和寄生组合继承(Parasitic Combination Inheritance)。它们都以下面这个函数为前提的
function object(o)
{
    function F(){}
    F.prototype = o;
    return new F();
}
先是定义F(),它相当于是个模板类,接着它的原型对象被指向了传入的参数o,F具有了o的属性和方法(作为原型属性和方法),最后返回一个模板类实例。 可以看出它的本质是基于对象的继承(新对象继承原对象的属性、方法,或者说是扩展)。下面是通过object()进行 原型继承的例子:
var person ={
    name : "sds",
    friends : ["sds1","sds2"]
};
var other = object(person);
other.showName = function(){return this.name;}
other.showFriends = function(){return this.friends;}
other.name = "sds3";
other.friends.push("sds4");
alert(other.showName());//sds3
alert(other.showFriends());//sds1,sds2,sds4
从object()定义我知道,other对象的原型是person,即name,friends属性是other的原型对象上的属性,任务对它们的改变都影响到其他对象(从person继承的,甚至person自己),在上面的示例基础上增加下面的代码:
alert(person.name);//sds
alert(person.friends);//sds1,sds2,sds4
var another=object(person);
alert(another.name);//sds
alert(another.friends);//sds1,sds2,sds4
正如前面所说的,原型属性(如friends)的改变将影响其他对象。寄生继承可以看作是对原型继承的增强,它在object()基础上提供了create(),如下代码
function create(o)
{
   var n = object(o);
   //定义新对象自己的属性和方法
   n.fun1 = function(){alert("Hello World");};
   //返回
   return n;
}
create()的用意很明确,相对于object()来说,新对象(通过原型)继承了o的属性、方法后,再定义新对象自己的属性、方法。套用时下最流行的做法:先把别人的照搬来,揉合点自己的,最后拿出去买。绝大部分的国产货就是这样的。
    object()并不是起clone作用的,n和o也是有着区别的,不能把n看作是o的clone副本。
    寄生组合继承,是另一种重要的继承。在yahoo! user interface库中的YAHOO.lang.extend()中使用。它主要是为了解决组合继承效率低的问题,因为组合继承中,会运行两次基类构造器。寄生组合继承核心代码是
function inherit(childType,baseType){//childType:子类构造器,baseType:基类构造器
    var proto = object(baseType.prototype);//基于基类原型对象创建一个对象,将作为子类原型对象
    proto.constructor = childType;//指定新原型对象的构造器属性为子类构造器
    childType.prototype = proto;//子类原型属性指向新的原型对象
}
inherit()实现了寄生组合继承的重要一个环节。注意这里只实现了对基类原型的继承。完整的实现可以参考如下代码:
function baseClass(name)
{
   this.name = name;
   this.colors = ["red","blue"];
}
baseClass.prototype.getName = function(){return this.name;};
function childClass(name,age)
{
   baseClass.call(this,name);
   this.age = age;
}
inherit(childClass,baseClass);
childClass.prototype.getAge = function(){return this.age;};//这句一定要放在inherit()之后,因inherit()会改变childClass.prototype的指向
var obj = new childClass("sds",50);
alert(obj.getName());//sds
alert(obj.getAge());//50
alert(obj.colors);//red,blue;
这样,寄生组合继承的实现效率要比组合继承高。原因是它不再new一个父类实例作为子类原型对象。
关于对象的clone,我认为可以参考下面的代码:
function clone(o)
{
    var obj ={};
    for(var p in o)
    {
        obj[p] = o[p];
    }
    return obj;
}
另关于原型对象上的属性有必要强调一点,对象的原型对象上的属性并不是对象的属性,但是对象可以访问(通过.或[])。in操作符可以访问对象上所有能访问的属性和方法。而hasOwnProperty()方法只能检测对象自身的属性和方法。考虑如下代码
var one = {"name":"sds","getName":function(){return this.name;}};
var two = object(one);//object()来自于前面的示例
alert("name" in two);//true
alert(two.hasOwnProperty("name"));//false;
two.name = "sds1";
alert(two.hasOwnProperty("name"));//true;
注意:在对two.name赋值操作后,two对象自身上会创建一个属性name,它有别于two的原型对象上的name属性,从此对two.name的 访问或赋值都将使用它自己的name属性,而原来位于原型上的name将束置高阁,闲置不用。这点在我们进行面向对象的js编程时要注意的,即在给对象的 原型上的属性赋值操作,会使对象本身添加同名属性,从而覆盖原型属性。
posted @ 2011-07-06 13:28  沈沈  阅读(139)  评论(0编辑  收藏  举报