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面向对象的多态特性!

发布了34 篇原创文章 · 获赞 1 · 访问量 15万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章