关于js继承学习系列之五:其他方式及总结[转]

      除前文学习的三种继承外,还有另外三种继承模式:原型继承(Prototypal Inheritance)、寄生继承(Parasitic Inheritance)和寄生组合继承(Parasitic Combination Inheritance)。它们都以下面这个函数为前提的

1 function object(o)
2 {
3 function F(){}
4 F.prototype = o;
5 return new F();
6 }


先是定义F(),它相当于是个模板类,接着它的原型对象被指向了传入的参数o,F具有了o的属性和方法(作为原型属性和方法),最后返回一个模板类实例。 可以看出它的本质是基于对象的继承(新对象继承原对象的属性、方法,或者说是扩展)。object()是原型继承的核心。下面是通过object()进行 原型继承的例子:

 1 var person ={
2 name : "sds",
3 friends : ["sds1","sds2"]
4 };
5 var other = object(person);
6 other.showName = function(){return this.name;}
7 other.showFriends = function(){return this.friends;}
8 other.name = "sds3";
9 other.friends.push("sds4");
10
11 alert(other.showName());//sds3
12 alert(other.showFriends());//sds1,sds2,sds4


从object()定义我知道,other对象的原型是person,即name,friends属性是other的原型对象上的属性,任务对它们的改变都影响到其他对象(从person继承的,甚至person自己),在上面的示例基础上增加下面的代码:

1 alert(person.name);//sds
2 alert(person.friends);//sds1,sds2,sds4
3
4 var another=object(person);
5 alert(another.name);//sds
6 alert(another.friends);//sds1,sds2,sds4


正如前面所说的,原型属性(如friends)的改变将影响其他对象。寄生继承可以看作是对原型继承的增强,它在object()基础上提供了create(),如下代码

1 function create(o)
2 {
3 var n = object(o);
4 //定义新对象自己的属性和方法
5 n.fun1 = function(){alert("Hello World");};
6
7 //返回
8 return n;
9 }


create()的用意很明确,相对于object()来说,新对象(通过原型)继承了o的属性、方法后,再定义新对象自己的属性、方法。套用时下最流行的做法:先把别人的照搬来,揉合点自己的,最后拿出去买。绝大部分的国产货就是这样的。
    object()并不是起clone作用的,n和o也是有着区别的,不能把n看作是o的clone副本。
    寄生组合继承,是另一种重要的继承。在yahoo! user interface库中的YAHOO.lang.extend()中使用。它主要是为了解决组合继承效率低的问题,因为组合继承中,会运行两次基类构造器。寄生组合继承核心代码是

1 function inherit(childType,baseType){//childType:子类构造器,baseType:基类构造器
2 var proto = object(baseType.prototype);//基于基类原型对象创建一个对象,将作为子类原型对象
3 proto.constructor = childType;//指定新原型对象的构造器属性为子类构造器
4 childType.prototype = proto;//子类原型属性指向新的原型对象
5 }


inherit()实现了寄生组合继承的重要一个环节。注意这里只实现了对基类原型的继承。完整的实现可以参考如下代码:

 1 function baseClass(name)
2 {
3 this.name = name;
4 this.colors = ["red","blue"];
5 }
6 baseClass.prototype.getName = function(){return this.name;};
7
8 function childClass(name,age)
9 {
10 baseClass.call(this,name);
11 this.age = age;
12 }
13 inherit(childClass,baseClass);
14 childClass.prototype.getAge = function(){return this.age;};//这句一定要放在inherit()之后,因inherit()会改变childClass.prototype的指向
15
16 var obj = new childClass("sds",50);
17 alert(obj.getName());//sds
18 alert(obj.getAge());//50
19 alert(obj.colors);//red,blue;


这样,寄生组合继承的实现效率要比组合继承高。原因是它不再new一个父类实例作为子类原型对象。

关于对象的clone,我认为可以参考下面的代码:

1 function clone(o)
2 {
3 var obj ={};
4 for(var p in o)
5 {
6 obj[p] = o[p];
7 }
8 return obj;
9 }


另关于原型对象上的属性有必要强调一点,对象的原型对象上的属性并不是对象的属性,但是对象可以访问(通过.或[])。in操作符可以访问对象上所有能访问的属性和方法。而hasOwnProperty()方法只能检测对象自身的属性和方法。考虑如下代码

1 var one = {"name":"sds","getName":function(){return this.name;}};
2 var two = object(one);//object()来自于前面的示例
3 alert("name" in two);//true
4 alert(two.hasOwnProperty("name"));//false;
5 two.name = "sds1";
6 alert(two.hasOwnProperty("name"));//true;


注意:在对two.name赋值操作后,two对象自身上会创建一个属性name,它有别于two的原型对象上的name属性,从此对two.name的 访问或赋值都将使用它自己的name属性,而原来位于原型上的name将束置高阁,闲置不用。这点在我们进行面向对象的js编程时要注意的,即在给对象的 原型上的属性赋值操作,会使对象本身添加同名属性,从而覆盖原型属性。

原文地址:https://www.cnblogs.com/405464904/p/2179585.html