Javascript对象继承

     在Javascript中,一切皆是对象,所谓的类也只是用来模拟其它面向对象语言的class的对象而已,例如:

function MyClass() {}//定义一个类
MyClass.call();//其实这个类本身也是一个对象

      在上面的代码中,并没有为MyClass定义call方法,但是却可以调用call方法,其原因就是JavaScript的原生对象在发挥作用。通过function关键字定义一个类,实质上就是实例化一个Function的实例,因为Javascript在Function的原生对象中定义了call方法,所以即使MyClass的定义是空的,但是还是可以调用call方法!由此,我们就可以看到继承的影子!
    在原生对象中定义的方法call被继承到了MyClass中,那么只要修改一下原生对象,那么就可以模拟出面向对象的继承机制了。

function MyBaseClass() {
    this.Add = function(a, b) {
        return a + b;
    }
}
function MyClass() {
 
}
MyClass.prototype = new MyBaseClass();
var obj = new MyClass();
var X = obj.Add(3, 4);

     只要把MyClass的原生对象指向基类MyBaseClass的实例对象,那么MyClass就可以继承MyBaseClass中的方法,从而实现了继承机制!

 

多继承

    任何对象的直接原生对象都只有一个,那么如果想实现多继承该怎么办呢?可以采用两种办法:
方法一:链状继承

function MyBaseClassA() {
     this.Add = function(a, b) {
         return a + b;
     }
 }
 function MyBaseClassB() {
     this.Sub = function(a, b) {
         return a - b;
     }
 }
 function MyClass() {
 }
 MyBaseClassB.prototype = new MyBaseClassA();
 MyClass.prototype = new MyBaseClassB();
 var obj = new MyClass();
 var X = obj.Add(3, 4);
 var Y = obj.Sub(9, 4);

方法二:拷贝继承

function MyBaseClassA() {
     this.Add = function(a, b) {
         return a + b;
     }
 }
 function MyBaseClassB() {
     this.Sub = function(a, b) {
         return a - b;
     }
 }
 function MyClass() {
 }
 var A = new MyBaseClassA();
 for (var method in A) {
     MyClass.prototype[method] = A[method];
 }
 var B = new MyBaseClassB();
 for (var method in B) {
     MyClass.prototype[method] = B[method];
 }
 var obj = new MyClass();
 var X = obj.Add(3, 4);
 var Y = obj.Sub(9, 4);

继承的本质就是属性拷贝,所以只要手动拷贝基类的所有属性,那么就可以实现多继承了,对于拷贝属性的代码可以封装一下,便于调用:

var Extend = function(DeriveClass,BaseClass) {
      var o = new BaseClass();
      for (var method in o) {
          DeriveClass.prototype[method] = o[method];
      }
  }
  Extend(MyClass, MyBaseClassA);
  Extend(MyClass, MyBaseClassB);

构造参数:

继承是实现了,但是如果有构造参数有又该怎么处理呢?答案就是在派生类中调用基类构造就可以了:

function MyBaseClass(a, b) {
        this.A = a;
        this.B = b;
        this.Add = function() {
            return this.A + this.B;
        }
    }
    function MyClass(a,b,c) {
        MyBaseClass.call(this, a, b);//调用基类的构造
    }
    var Extend = function(DeriveClass, BaseClass) {
        var o = new BaseClass();
        for (var method in o) {
            DeriveClass.prototype[method] = o[method];
        }
    }
    Extend(MyClass, MyBaseClass);
    var obj = new MyClass(4,5,8);
    var X = obj.Add();
    alert(X);        //结果:9

     call和apply方法是经常用到的两个方法,其作用就是在另一个域内调用方法!

    继承机制带来的另一个问题就是同名方法隐藏问题!Javascript对象都是由原型对象生成,原型对象也有其自己的原型对象,这样就构成了一条原型对象链,对象链的顶端指向Object原生对象,末端就是对象本身,如果对象链中存在同名的方法,那么对象链末端的方法访问优先级高于顶端的优先级,因此派生类的方法总是隐藏基类的方法:

var BaseClass=function(){
    this.Hello=function(){
        return "A";
    }
    this.say=function(){
        return "Saying A";
    }
}
var BaseObj = new BaseClass();
var X = BaseObj.Hello();
alert(X);        //结果:A
BaseClass.prototype.Hello=function(a,b){
        return "B";
    }
var Y = BaseObj.Hello();
alert(Y);        //结果:A
var MyClass = function(){
    this.Hello=function(){
        return "C";
    }
}
var Extend = function(DeriveClass, BaseClass) {
        var o = new BaseClass();
        for (var method in o) {
            DeriveClass.prototype[method] = o[method];
        }
    }
Extend(MyClass, BaseClass);
var MyObj = new MyClass();
var Z = MyObj.Hello();
alert(Z);        //结果:C
MyClass.prototype.Hello=function(){
        return "D";
    }
MyClass.prototype.say=function(){
        return "Saying D";
    }
var K = MyObj.Hello();
alert(K);        //结果:C
var L = MyObj.say();
alert(L);        //结果:Saying D

     方法隐藏的唯一准则就是原型对象链的顺序,方法是否会被隐藏与实现继承的机制相关!

     以后再说一说Javascript面向对象的多态特性!

 

 

原发布于Javascript对象继承(2009-05-07 22:14),现转于此!

posted @ 2012-05-21 17:53  Charles-Lee  Views(595)  Comments(0)    收藏  举报