没那么简单 那些应该吃透的JavaScript概念(1)(3)
六,继承
如果两个类都是同一个实例的类型,那么它们之间存在着某种关系,我们把同一个实例的类型之间的泛化关系称为继承。C#和JAVA中都有这个,具体的理解就不说了。在JavaScript中,并不直接从方法上支持继承,但是就像前面说的,可以模拟。
方法可以归纳为四种:构造继承法,原型继承法,实例继承法和拷贝继承法。融会贯通之后,还有混合继续法,这是什么法,就是前面四种挑几种混着来。以下例子来源于王者归来,其中涉及到了apply,call和一些Array的用法,有兴趣的可以自己在园子里搜索一下。
1,构造继续法例子:
- //定义一个Collection类型
- functionCollection(size)
- {
- this.size=function(){returnsize};//公有方法,可以被继承
- }
- Collection.prototype.isEmpty=function(){//静态方法,不能被继承
- returnthis.size()==0;
- }
- //定义一个ArrayList类型,它"继承"Collection类型
- functionArrayList()
- {
- varm_elements=[];//私有成员,不能被继承
- m_elements=Array.apply(m_elements,arguments);
- //ArrayList类型继承Collection
- this.base=Collection;
- this.base.call(this,m_elements.length);
- this.add=function()
- {
- returnm_elements.push.apply(m_elements,arguments);
- }
- this.toArray=function()
- {
- returnm_elements;
- }
- }
- ArrayList.prototype.toString=function()
- {
- returnthis.toArray().toString();
- }
- //定义一个SortedList类型,它继承ArrayList类型
- functionSortedList()
- {
- //SortedList类型继承ArrayList
- this.base=ArrayList;
- this.base.apply(this,arguments);
- this.sort=function()
- {
- vararr=this.toArray();
- arr.sort.apply(arr,arguments);
- }
- }
- //构造一个ArrayList
- vara=newArrayList(1,2,3);
- dwn(a);
- dwn(a.size());//a从Collection继承了size()方法
- dwn(a.isEmpty);//但是a没有继承到isEmpty()方法
- //构造一个SortedList
- varb=newSortedList(3,1,2);
- b.add(4,0);//b从ArrayList继承了add()方法
- dwn(b.toArray());//b从ArrayList继承了toArray()方法
- b.sort();//b自己实现的sort()方法
- dwn(b.toArray());
- dwn(b);
- dwn(b.size());//b从Collection继承了size()方法
2,原型继承法例子
- //定义一个Point类型
- functionPoint(dimension)
- {
- this.dimension=dimension;
- }
- //定义一个Point2D类型,"继承"Point类型
- functionPoint2D(x,y)
- {
- this.x=x;
- this.y=y;
- }
- Point2D.prototype.distance=function()
- {
- returnMath.sqrt(this.x*this.x+this.y*this.y);
- }
- Point2D.prototype=newPoint(2);//Point2D继承了Point
- //定义一个Point3D类型,也继承Point类型
- functionPoint3D(x,y,z)
- {
- this.x=x;
- this.y=y;
- this.z=z;
- }
- Point3D.prototype=newPoint(3);//Point3D也继承了Point
- //构造一个Point2D对象
- varp1=newPoint2D(0,0);
- //构造一个Point3D对象
- varp2=newPoint3D(0,1,2);
- dwn(p1.dimension);
- dwn(p2.dimension);
- dwn(p1instanceofPoint2D);//p1是一个Point2D
- dwn(p1instanceofPoint);//p1也是一个Point
- dwn(p2instanceofPoint);//p2是一个Point
以上两种方法是最常用。
3,实例继承法例子
在说此法例子之前,说说构造继承法的局限,如下:
- functionMyDate()
- {
- this.base=Date;
- this.base.apply(this,arguments);
- }
- vardate=newMyDate();
- alert(date.toGMTString);//undefined,date并没有继承到Date类型,所以没有toGMTString方法
核心对象的某些方法不能被构造继承,原因是核心对象并不像我们自定义的一般对象那样在构造函数里进行赋值或初始化操作换成原型继承法呢?,如下:
- functionMyDate(){}
- MyDate.prototype=newDate();
- vardate=newMyDate();
- alert(date.toGMTString);//'[object]'不是日期对象,仍然没有继承到Date类型!
现在,换成实例继承法:
- functionMyDate()
- {
- varinstance=newDate();//instance是一个新创建的日期对象
- instance.printDate=function(){
- document.write("<p>"+instance.toLocaleString()+"</p>");
- }//对instance扩展printDate()方法
- returninstance;//将instance作为构造函数的返回值返回
- }
- varmyDate=newMyDate();
- dwn(myDate.toGMTString());//这回成功输出了正确的时间字符串,看来myDate已经是一个Date的实例了,继承成功
- myDate.printDate();//如果没有returninstance,将不能以下标访问,因为是私有对象的方法
4,拷贝继承法例子
- Function.prototype.extends=function(obj)
- {
- for(vareachinobj)
- {
- this.prototype[each]=obj[each];
- //对对象的属性进行一对一的复制,但是它又慢又容易引起问题
- //所以这种“继承”方式一般不推荐使用
- }
- }
- varPoint2D=function(){
- //……
- }
- Point2D.extends(newPoint())
- {
- //……
- }
这种继承法似乎是用得很少的。
5,混合继承例子
- functionPoint2D(x,y)
- {
- this.x=x;
- this.y=y;
- }
- functionColorPoint2D(x,y,c)
- {
- Point2D.call(this,x,y);//这里是构造继承,调用了父类的构造函数
- //从前面的例子看过来,这里等价于
- //this.base=Point2D;
- //this.base.call(this,x,y);
- this.color=c;
- }
- ColorPoint2D.prototype=newPoint2D();//这里用了原型继承,让ColorPoint2D以Point2D对象为原型






