function Animal(){
}
Animal.prototype = {
group : '',
gender : '',
eat : function(){
return 'Yum , food! nom nom';
},
sleep : function(){
return 'zzzzzz...';
}
}
function Bird(){
}
function extend(subClass,superClass){
        /*声明一个空构造函数*/
function fn(){}
        /*将空函数原型指向父类,这样fn就有了superClass成员了,fn是为下面子类继承做准备用的。*/
fn.prototype = superClass.prototype;
        /*将子类的原型指向空函数的实例*/
subClass.prototype = new fn();
        /*因为前面改变了子类构造函数的原型会影响constructor属性(指向Object了),所以重新指定一下子类的constructor属性*/
subClass.prototype.constructor = subClass;
        /*添加一个属性,保存子类的父类构造函数*/
subClass.baseConstructor = superClass;
        /*添加一个属性,保存子类的父类构造函数原型*/
subClass.__super__ = superClass.prototype;
}
extend(Bird , Animal);
var bird = new Bird();
console.log(bird.eat());今天在书上看到这段代码,自己动手试了下,运行成功后,感觉这代码有点眼熟,然后打开Extjs的ext-all-debug.js源码,找到extend方法。果然神似,曾经看的头晕的代码,今天终于明白了,发帖来跟大家分享下,加了点注释,不对的地方希望大家拍砖指正,谢谢。

解决方案 »

  1.   

    空函数继承,很好...
    我来个:
    function Animal(){
            }
            Animal.prototype = {
                group : '',
                gender : '',
                eat : function(){
                    return 'Yum , food! nom nom';
                },
                sleep : function(){
                    return 'zzzzzz...';
                },
                walk : {
                    "method" : "walk"
                }
            }
            function Bird(){
            }
            function Person(){
            }
            function extend(subClass,superClass){
                /*声明一个空构造函数*/
                function fn(){}
                /*将空函数原型指向父类,这样fn就有了superClass成员了,fn是为下面子类继承做准备用的。*/
                fn.prototype = superClass.prototype;
                /*将子类的原型指向空函数的实例*/
                subClass.prototype = new fn();
                /*因为前面改变了子类构造函数的原型会影响constructor属性(指向Object了),所以重新指定一下子类的constructor属性*/
                subClass.prototype.constructor = subClass;
                /*添加一个属性,保存子类的父类构造函数*/
                subClass.baseConstructor = superClass;
                /*添加一个属性,保存子类的父类构造函数原型*/
                subClass.__super__ = superClass.prototype;
            }
            extend(Bird , Animal);
            extend(Person , Animal);
            var bird = new Bird();
            var person = new Person();        bird.walk.method = "fly";
            console.log(person.walk.method);结果是神马呢?不错就是 fly,在使用new 操作符后,内部对象并没有新建拷贝..真令人沮丧...
    要小心这种情况带来的程序出错,也算是空函数继承的一个小小bug吧。
      

  2.   


    /*将子类的原型指向空函数的实例*/
        subClass.prototype = new fn();为什么要new fn(),直接fn.prototype 不行吗?new fn()是直接继承自fn.prototype
      

  3.   


    function extend(subClass,superClass){
        if(Object.create){
            subClass.prototype=Object.create(superClass.prototype,{});
        }
        else{
            function fn(){}
            fn.prototype = superClass.prototype;
            subClass.prototype = new fn();
        }
        subClass.prototype.constructor = subClass;    
        subClass.baseConstructor = superClass;
        subClass.__super__ = superClass.prototype;    
    }
      

  4.   


    extend : function(){
        // inline overrides
        var io = function(o){
          for(var m in o){
            this[m] = o[m];
          }
        };
        var oc = Object.prototype.constructor;    return function(sb, sp, overrides){
          if(typeof sp == 'object'){
            overrides = sp;
            sp = sb;
            sb = overrides.constructor != oc ? overrides.constructor : function(){
              sp.apply(this, arguments);
            };
          }
          var F = function(){},
          sbp,
          spp = sp.prototype;      F.prototype = spp;
          sbp = sb.prototype = new F();
          sbp.constructor=sb;
          sb.superclass=spp;
          if(spp.constructor == oc){
            spp.constructor=sp;
          }
          sb.override = function(o){
            Ext.override(sb, o);
          };
          sbp.superclass = sbp.supr = (function(){
            return spp;
          });
          sbp.override = io;
          Ext.override(sb, overrides);
          sb.extend = function(o){
            return Ext.extend(sb, o);
          };
          return sb;
        };
      }()这是100%的extjs 3.3.1的扩展函数,你看看有什么区别!
      

  5.   

    上面这些代码是按书上打的。原型继承也确实存在这个问题,如果数据类型是引用型的,比如:[],{},一个对象修改后,其它对象也会修改。
    所以一般用组合继承,prototype加apply或call。把方法写在原型上,属性写在构造函数里面。
    如下:function Animal(group,gender,walk){
    this.group = group;
    this.gender = gender;
    this.walk = walk;
    }
    Animal.prototype = {
    eat : function(){
    return 'Yum , food! nom nom';
    },
    sleep : function(){
    return 'zzzzzz...';
    }
    }
    function Bird(group,gender,walk){
    Animal.call(this,group,gender,walk);
    }
    function Person(group,gender,walk){
    Animal.call(this,group,gender,walk);
    }
    function extend(subClass,superClass){
    /*声明一个空构造函数*/
    function fn(){}
    /*将空函数原型指向父类,这样fn就有了superClass成员了,fn是为下面子类继承做准备用的。*/
    fn.prototype = superClass.prototype;
    /*将子类的原型指向空函数的实例*/
    subClass.prototype = new fn();
    /*因为前面改变了子类构造函数的原型会影响constructor属性(指向Object了),所以重新指定一下子类的constructor属性*/
    subClass.prototype.constructor = subClass;
    /*添加一个属性,保存子类的父类构造函数*/
    subClass.baseConstructor = superClass;
    /*添加一个属性,保存子类的父类构造函数原型*/
    subClass.__super__ = superClass.prototype;
    }
    extend(Bird , Animal);
    extend(Person , Animal);
    var bird = new Bird('aa','bb',{method:'walk'});
    var person = new Person('cc','dd',{method:'xxx'});
    bird.walk.method = "fly";
    console.log(person.walk.method);
      

  6.   

    我说像的是继承的那几段代码,Extjs的extend方法还给子类添加静态方法:override,实例方法:override,extend。还有其它一些。
      

  7.   

    引用错了
    我说像的是继承的那几段代码,Extjs的extend方法还给子类添加静态方法:override,实例方法:override,extend。还有其它一些。