JS虽然没有类的概念,但JS的灵活性可以让我们用各种办法去实现面向对象
关于继承的实现,应该有各种各样的办法
先抛个砖,这是我实现的办法之一
之前也有不同的办法实现过,但觉得这个办法更好些,而且代码很少
<html>
<head>
    <title></title>
</head>
<body>
<script type="text/javascript">
    //扩展方法的定义,不得不污染一下 Function 了
    Function.prototype.extend = function (base, ppt) {
        var attr = null;
        for (attr in base.prototype) {
            //复制每个基类的prototype成员
            this.prototype[attr] = base.prototype[attr];
        }        for (attr in ppt) {
            if (this.prototype[attr] != null) {
                //发现同名方法,重载
                var fold = this.prototype[attr];   //旧方法
                var fnew = ppt[attr];   //新的重载方法
                fnew.base = fold;  //附加base属性
                this.prototype[attr] = fnew; //重载
            }
            else {
                //添加
                this.prototype[attr] = ppt[attr];
            }
        }
    };
    Function.base = "(arguments.callee.base.apply(this, arguments))";    //基类定义
    function Base(name) {
        this.name = name;
    }
    Base.prototype = {
        getName: function () {
            return this.name;
        }
    };    //扩展类1
    function MyClass1(name) {
        //调用父类构造方法
        Base.call(this, name);
    }
    //扩展自Base类
    MyClass1.extend(Base, {
        //新的方法
        showName: function () {
            alert(this.getName());
        },
        //这个方法与父类同名,将被重载
        getName: function () {
            var name = eval(Function.base); //调用父类(Base)的同名方法
            return name + "(MyClass1附加的信息)";
        }
    });    //扩展类2
    function MyClass2(name) {
        //调用父类构造方法
        MyClass1.call(this, name);
    }
    MyClass2.extend(MyClass1, {
        //再次重载
        getName: function () {
            var name = eval(Function.base); //调用父类(MyClass1)的同名方法
            return name + "(MyClass2附加的信息)";
        }
    });    var inst = new MyClass2("MyClass2实例");
    inst.showName();
</script>
</body>
</html>
如果有什么bug欢迎指出,如果有其它的办法实现,不妨贴出来讨论一下

解决方案 »

  1.   

    楼主的这种继承方案就是传说中的掺元类我这里也有个方案,是YUI的一种继承体系:<script type="text/javascript">
    var Class = {
    extend:function(subClass,superClass){
    var F = function(){};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;

    subClass.superclass = superClass.prototype;
    if(superClass.prototype.constructor == Object.prototype.constructor) {
    superClass.prototype.constructor = superClass;
    }
    }
    /**
     * 调用父类的构造函数
     * @param subClass 子类函数名
     * @param subInstance 子类对象引用
     */
    ,callSuper:function(subClass,subInstance){
    var argsArr = [];

    for(var i=2,len=arguments.length; i<len; i++) {
    argsArr.push(arguments[i]);
    }

    subClass.superclass.constructor.apply(subInstance, argsArr);  
    }
    /**
     * 子类中调用父类的函数
     * @param subClass 子类函数名
     * @param subInstance 子类对象引用
     * @param methodName 父类方法名
     */
    ,runSuperMethod:function(subClass,subInstance,methodName) {
    return subClass.superclass[methodName].call(subInstance);
    }};// Demo
    // 声明父类
    var Person = function(param){
    this.name = param.name;
    this.age = param.age;
    }
    Person.prototype.sayName = function(){
    alert("My name is " + this.name);
    }
    Person.prototype.sayAge = function(){
    alert("My age is " + this.age);
    }
    Person.prototype.getAge = function(){
    return this.age;
    }
    // 声明子类
    var Man = function(param){
    // 调用父类的构造函数
    Class.callSuper(Man,this,param);
    }
    // 继承父类
    Class.extend(Man,Person);// 覆盖父类的sayAge方法
    Man.prototype.sayAge = function(){
    alert(this.name + "'s age is " + this.age);
    }
    // 覆盖父类的方法,并且调用父类原来的方法
    Man.prototype.getAge = function(){
    // 先调用父类方法返回年龄
    var age = Class.runSuperMethod(Man,this,'getAge');
    // 年龄+1
    alert(this.name + "'s age is " + (age + 1));
    }
    // 测试
    var man = new Man({name:"Jim",age:22});
    man.sayName(); // 这里调用父类的方法
    man.sayAge();  // 这里调用自己的方法
    man.getAge();  
    </script>
    详见:YUI-extend
      

  2.   

    function Base()
    {
        this.x = 1;
    }function Sub()
    {
        Base.call(this);
    }
    最方便
      

  3.   

    类的继承应该要实现了instanceof这个操作,下面的继承是自己写的:var Class={
    createClass:function(c,p){
    var C=p?c:(c&&c.isFunction())?c:(c&&c.constructor).isFunction()?c.constructor:function(){};
    if(!p)delete c.constructor;else delete p.constructor;
    C.prototype=C.prototype||{};
    C.prototype.copy(p?p:c);
    C.prototype.constructor=C;
    try{return C}catch(ex){}finally{c=p=C=null}
    },
    extend:function(sub,sup,p){
    sup=sup||{};
    if(sup && sup.isObject()){
    var oc=Object.prototype.constructor;
    p=sup;
    sup=sub;
    sub=p.constructor==oc?function(){arguments.callee.superclass.apply(this,arguments)}:p.constructor;
    oc=null;
    }
        
    if(sup.prototype.constructor!=sup)sup.prototype.constructor=sup;
    var F=function(){};F.prototype=sup.prototype;
    var tmp=sub.prototype;
    if(sub.superclass){
    sub.prototype=tmp;
    sub.prototype.copyIf(new F(),true);
    sub.prototype.copy(p);
    }
    else{
    sub.prototype=new F();
    sub.prototype.copy(tmp);
    sub.prototype.copy(p);
    sub.superclass=sup;
    }
    sub.prototype.constructor=sub;
    try{return sub}catch(ex){}finally{F=tmp=sup=sub=p=null}
    }
    };目测1 3楼都没实现
      

  4.   


    光靠目测是没用的,跑一把吧alert(man instanceof Person) // true
    alert(man instanceof Man) // true
      

  5.   

    Extjs的extend函数:function(subclass, superclass, overrides) {
                    // First we check if the user passed in just the superClass with overrides
                    if (Ext.isObject(superclass)) {
                        overrides = superclass;
                        superclass = subclass;
                        subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
                            superclass.apply(this, arguments);
                        };
                    }                //<debug>
                    if (!superclass) {
                        Ext.Error.raise({
                            sourceClass: 'Ext',
                            sourceMethod: 'extend',
                            msg: 'Attempting to extend from a class which has not been loaded on the page.'
                        });
                    }
                    //</debug>                // We create a new temporary class
                    var F = function() {},
                        subclassProto, superclassProto = superclass.prototype;                F.prototype = superclassProto;
                    subclassProto = subclass.prototype = new F();
                    subclassProto.constructor = subclass;
                    subclass.superclass = superclassProto;                if (superclassProto.constructor === objectConstructor) {
                        superclassProto.constructor = superclass;
                    }                subclass.override = function(overrides) {
                        Ext.override(subclass, overrides);
                    };                subclassProto.override = inlineOverrides;
                    subclassProto.proto = subclassProto;                subclass.override(overrides);
                    subclass.extend = function(o) {
                        return Ext.extend(subclass, o);
                    };                return subclass;
                };
      

  6.   

    我有个问题,thc1987提出的YUI和ExtJs的继承方案,都有一个地方就是constructor的赋值
    而我的方案中并不去理会这个 constructor,会存在什么风险吗?
      

  7.   

    举个例子:var base=function(){};
    var sub=function(){};
    sub.prototype=new base();//原型方式扩展
    var t1=new sub();
    alert(t1 instanceof base);//弹出true为实现那个constructor主要是在今后很方便,通过一个实例可以获取它的构造类,加上superclass可以获取父类的构造类。
      

  8.   

    instanceof 依靠constructor来判断?
      

  9.   


    不是,instanceof判断一个对象是否是一个类的实例,具体机制不好解释,跟原型链有关,而那个constructor是获取一个对象的构造器或构造函数:var a={};//a=1 a=false a='a' a=new Date() a=Math a=/ /g ……
    alert(a.constructor)
    var classA=function(){}
    a=new classA();
    alert(a.constructor===classA);
    alert(classA.prototype.constructor===classA);在函数扩展中对constructor的控制很重要,以9楼中的那个例子:var base=function(){};
    var sub=function(){};
    sub.prototype=new base();//原型方式扩展
    var t1=new sub();
    alert(t1.constructor===base);
    /**
     * 这里表示对象t1的构造器为base而不是sub(原型扩展方式的缺陷,而extjs yui的扩展方式都是这个方式),
     * 因为sub的原型被指向了base的一个实例,而任意一个base实例都有一个constructor属性,该属性指向base,所以sub的原型中就有一个指向base的constructor属性,即:sub.prototype.constructor=base
      alert(sub.prototype.constructor===base);
     */所以在你想要实现js中的继承时需要考虑如下要点:以base为父类 sub为子类 ob为父类实例 os为子类实例
    1.ob isA base
    2.os isA sub
    3.os isA base
    4.ob.constructor===base
    5.os.constructor===sub以上5点为必要的,前三点通过原型链的继承方式可以实现,后两点需要在继承后人为地指定各自的构造器。至于superlcass,实现sub.superlcass===base,这个根据自己的需要,方便今后使用。extjs是把子类的superclass设置为了父类的prototype,方便寻找父类的静态(公共)方法和属性,即sub.superclass=base.prototype
      

  10.   

    对象冒充function ClassA(sColor)
    {
      this.color = sColor;
      this.sayColor = function() {
      alert(this.color);
     }
    }
    function ClassB(sColor)
    {
      this.newMethod = ClassA;
    this.newMethod(sColor); 
    delete this.newMethod; 
    }