02.Javascript中的继承----Inherits

 

02.Javascript中的继承----Inherits

本文不再过多的阐述OOP中继承的概念,只是用原生的Javascript代码来模拟类继承(不是对象扩展)

类继承:inherits

假设有已定义好的超类(父类)SuperClass和待继承的子类SubClass,于是,可以定义如下的方法来实现类继承

inherits方法的定义

如下的这个inherits方法,其实现思想主要参考《Pro JavaScript Design Patterns》【Ross Harmes and Dustin Diaz】

/**
 * 这个方法用来实现类继承
 * @param {function} subClass 待继承的子类
 * @param {function} superClass 待被继承的父类
 * @exception {Error} 参数不合法时抛出异常
 */
var inherits = function(subClass,superClass){
    if(arguments.length !== 2){
        throw new Error("必须明确的指定子类和父类");
    }
    for(var i = 0,n = arguments.length;i < n;i++){
        if(typeof arguments[i] !== "function"){
            throw new Errorr("所给的子类和父类必须都是function");
        }
    }
    var F = function(){};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;    
};

该方法的内部会进行严格的参数合法性检查,参数必须是两个,即一个子类,一个父类;另外还要求两个参数都必须是function类型,否则抛出异常,宣告继承失败

inherits方法的使用

▲第一步
/**
 * 定义父类
 */
var SuperClass = function(){};
SuperClass.prototype = {
    name : "赵先烈",
    talk : function(){
        alert("我的名字叫" + this.name);
    }
};    

/**
 * 这里定义子类
 */
var SubClass = function(){};    

//实施继承
inherits(SubClass,SuperClass);

//创建子类并从调用从子类继承过来的方法
var oSub = new SubClass();
oSub.talk();    //这里输出:我的名字叫赵先烈

从程序的执行结果可以看出,这种继承方法是将父类中的全部内容(除构造器以外)拷贝到子类中来,顺利的完成了类继承。

▲第二步
/**
 * 这里定义父类
 */
var SuperClass = function(){
    this.name = "赵先烈";
    this.talk = function(){
        alert("我的名字叫" + this.name);
    };
};

/**
 * 这里定义子类
 */
var SubClass = function(){
    //这是一个空类
};

//实施继承
inherits(SubClass,SuperClass);

//创建子类对象,并调用从父类继承过来的方法
var oSub = new SubClass();
oSub.talk();    //按照继承的概念,这里应该输出:我的名字叫赵先烈

程序真正执行后,才发现发生异常了,原因:在oSub实例中不存在talk方法。不是已经通过inherits方法实现继承了么,为什么会没有这个 方法呢?探究其原因,是因为在inherits的内部,只是将SuperClass的原型链原样的拷贝给了SubClass,而不在SuperClass 原型链中的属性及方法,子类就拿不到了。

那么,既要支持第一种继承,也要能满足第二种,我们只能再次对inherits方法进行升级了,将其改为如下形式:

/**
 * 这个方法用来实现类继承
 * @param {function} subClass 待继承的子类
 * @param {function} superClass 待被继承的父类
 * @exception {Error} 参数不合法时抛出异常
 */
var inherits = function(subClass,superClass){
    if(arguments.length !== 2){
        throw new Error("必须明确的指定子类和父类");
    }
    for(var i = 0,n = arguments.length;i < n;i++){
        if(typeof arguments[i] !== "function"){
            throw new Errorr("所给的子类和父类必须都是function");
        }
    }
    subClass.prototype = new superClass();
    subClass.prototype.constructor = subClass;
};

经过这样的改动,第一步和第二步中的情况就都能顺利的正常的执行了。

▲第三步

如果在第二步的基础上,将代码中的SubClass.prototype改为如下形式:

SubClass.prototype = {
    walk : function(){ 
        alert("偶也,我可以走路了哎");
    },
    talk : function(){
        alert("我的名字不叫" + this.name);
    }

};

再执行如下代码:

inherits(SubClass,SuperClass);

var oSub = new SubClass();
oSub.talk();    //这里仍然输出:我的名字叫赵先烈
//重点在下面这句
oSub.walk();    //这里会抛出异常,告诉我们,walk方法不存在

分析这个结果,oSub.talk()的输出应该为:我的名字不叫赵先烈。并且oSub.walk()也应该有输出,程序应该正常执行才对。但是,为什么会有这样的运行结果呢?

这到底是为什么呢?相信你一定早就发现了,在inherits方法中有这样一句关键的代码:

subClass.prototype = new superClass();

这里已经告诉我们,原来,子类中的原型链已经被完全替换了,其实仔细说起来,这样做是有违继承的原则的(一般不都是子类覆盖父类么?怎么 反过来了呢)。

但是这样的问题我们始终要解决,必须让这个所谓的继承能同时满足以上三种情况都能正常执行。苦思冥想后,决定改成这样:

/**
 * 这个方法用来实现类继承
 * @param {function} subClass 待继承的子类
 * @param {function} superClass 待被继承的父类
 * @exception {Error} 参数不合法时抛出异常
 */
var inherits = function(subClass,superClass){
    if(arguments.length !== 2){
        throw new Error("必须明确的指定子类和父类");
    }
    for(var i = 0,n = arguments.length;i < n;i++){
       if(typeof arguments[i] !== "function"){
            throw new Errorr("所给的子类和父类必须都是function");
        }
    }

    var oSuper = new superClass();
    for(var key in oSuper){
        if(!subClass.prototype[key]){
            subClass.prototype[key] = oSuper[key];
        }
    }
    subClass.prototype.constructor = subClass;
};

OK,通过这样的升级,再次运行上面的代码,顺利通过了。

上面这个通过两次升级的inherits方法也是目前比较稳定的版本了,在后续的文章中所指的inherits方法,就是这个了。

本文旨在共同探讨Javascript中类的继承方式,只是其中的一种模拟方式,模拟之不当,还请见谅。

欢迎提出宝贵的升级建议。

 

你可能感兴趣的:(Javascript设计模式)