无梦空间

JavaScript极限编程

导航

6)类的继承

    1)利用共享prototype原型对象实现继承.
    继承是面向对象开发的一个重要概念.在JavaScript中没有专门的机制来实现类的继承,但可以通过拷贝一个类的prototype到另外一个类实现继承.一种简单的继承实现如下:
fucntion class1(){
      
//构造函数
}

function class2(){
      
//构造函数
}
class2.prototype
=class1.prototype;
class2.prototype.moreProperty1
="xxx";
class2.prototype.moreMethod1
=function(){
      
//方法实现代码
}
var obj=new class2();
    这样,首先是class2具有了class1一样的prototype,不考虑构造函数,两个类是等价的.随后,又通过prototype给class2 赋予了两个额外的方法,所以class2是在class1的基础上增加了属性和方法,这就实现了类的继承.
    JavaScript提供了instanceof操作符来判断一个对象是否是某个类的实例,对于上面创建的obj对象,下面两条语句都是成立的:
obj instanceof class1
obj 
instanceof class2
    表面上看,上面的实现完全可行,JavaScript也能正确理解这种继承关系,obj同时是class1和class2的实例.但是事实上是不对的,JavaScript的这种理解实际上是基于一种很简单的策略,如下
,先使用prototype让class2继承于class1,再在class2中重复定义method方法:
//定义class1
function class1(){
      
//构造函数
}
//定义class1的成员
class1.prototype={
      m1:
function(){
            alert(
1);
      }
}

//定义class2
function class2(){
      
//构造函数
}
//让class2继承于class1
class2.prototype=class1.prototype;
//给class2重复定义方法method
class2.prototype.method=function(){
      alert(
2);
}

//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用两个对象的method方法
obj1.method();
obj2.method();
    (明白了,这里用prototype等于基类的prototype来实现,在改变子类的prototype属性(方法)的时候,会影响到基类的属性(方 法),这显然大大不对啦.解决的方法,应该是拷贝基类的prototype属性,而不应该是赋予.)
    这里弹出了两次对话框"2",可见,当对class2进行prototype的改变时,class1的prototype也随之改变,即使对class2 的prototype增减一些成员,class1的成员也随之改变.这里的奥秘是:
class1和class2的prototype是完全相同的,是对同一个对象的引用.
    在JavaScript中,除了基本的数据类型(数字\字符串\布尔等),所有的赋值以及函数参数都是引用传递,而不是值传递.(这与C#类似,也是
JavaScript提高性能的一个手段.)
    上面的  
class2.prototype=class1.prototype;   语句,仅仅是让class2的prototype对象引用class1的prototype,造成了基类与子类的成员定义始终保持一致的效果.
   
从这里也看到了instanceof操作符的执行机制,它就是判断一个对象是否是一个prototype的实例,因为这里的obj1和obj2都是对应于同一个prototype,所以它们instanceof的结果都是相同的。
    因此,使用prototype引用拷贝实现继承不是正确的方法.下面,利用反射机制和prototype来实现正确的类继承.

    2)利用反射机制和prototype实现继承.
    利用反射机制实现类的继承,思路如下:利用for(...in...)语句遍历出所有基类的prototype的成员,并将其赋值给子类的prototype对象,例如:
   
//class1
function class1(){
      
//构造函数
}
class1.prototype
={
      method:
function(){
           alert(
1);
      },
      method2:
function(){
           alert(
"method2");
      }
}

//class2
function class2(){
      
//构造函数
}
//让class2继承于class1
for(var p in class1.prototype){     //遍历class1.prototype的属性和方法
   if (class2.prototype[p] == null//如果类class2中没有此属性或方法,则进行拷贝
        class2.prototype[p]=class1.prototype[p];
}
//覆盖定义class1中的method方法
class2.prototype.method=function(){
      alert(
2);
}


//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();
  
从运行结果可见,obj2中重复定义的method已经覆盖了继承的method方法,同时method2方法未受影响。而且obj1中的method方法仍然保持了原有的定义。这样,就实现了正确意义的类的继承.
    为了方便开发,可以为每个类添加一个共有的方法,用以实现类的继承:
Function.prototype.inherit = function(baseClass){
    
for (var p in baseClass.prototype){
        
if (this.prototype[p] == null){
            
this.prototype[p] = baseClass.prototype[p];
        }
    }
}
    这里使用所有函数对象(类)的共同类Function来添加继承方法,这样所有的类都会有一个inherit方法,用以实现基于prototype的继承.
   
    3)prototype.js框架中
的类继承实现机制.
    在
prototype.js框架中,首先为所有的对象定义一个extend方法:

    Object.extend方法很容易理解,它是Object类的一个静态方法(只能用"类名.方法名"的形式调用),用于将参数中source的所有属性都赋值到destination对象中,并返回destination对象.
    而
Object.prototype.extend,因为Object是所有对象的基类,因此这里是为所有对象添加一个extend方法,出于代码复用的角度,使用了如下语句:
       Object.extend.apply(this,[this,object]);
    这一句是将Object类的静态方法作为对象的方法运行,第一个参数this是指向对象实例自身(这里无所谓);第二个参数是一个数组,包括两个元素:对象本身和传进来的对象参数object.
    如下类继承实现:
//为Object类添加静态方法:extend
Object.extend = function(destination, source) {
  
for(property in source) {
     
if (destination[property] == null){
        destination[property] 
= source[property];
     }
  }
  
return destination;
}

//class1
function class1(){
      
//构造函数      
}
class1.prototype
={
      age:
"sss",
      method:
function(){
           alert(
1);
      },
      method2:
function(){
           alert(
"method2");
      }
}
class1.show 
= function(){
    alert(
"class1的静态方法");
}

//class2
function class2(){
      
//构造函数
}

//覆盖定义class1中的method方法
class2.prototype.method=function(){
      alert(
2);
}

//Object.extend时,子类与父类必须一致.
Object.extend(class2.prototype,class1.prototype);   //继承常规属性和方法
Object.extend(class2,class1);                       //继承静态属性和方法

//创建两个类的实例
var obj1=new class1();
var obj2=new class2();
//分别调用obj1和obj2的method方法
obj1.method();
obj2.method();
//分别调用obj1和obj2的method2方法
obj1.method2();
obj2.method2();

class2.show();
   

posted on 2006-08-16 11:09  想那风霜雪  阅读(343)  评论(0编辑  收藏  举报