Ext.extend() 使用


一、从实际使用角度分析Ext.extend()函数
     还是先贴出Ext核心代码里面完成继承功能的这段经典代码:
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.override = io;
                Ext.override(sb, overrides);
                sb.extend = function(o){Ext.extend(sb, o);};
                return sb;
            };
        }()
     使用Ext.extend()这个函数来做继承,可以有三种写法:
1、 子类本身有自己的构造函数;
2、 不提供子类自己的构造函数,使用父类的构造函数来构造子类;
3、 在第三个参数overrides里面提供一个constructor函数,然后在它的第一句调用父类的构造


来看第一种写法(子类有自己定义的构造函数),例如:
A=function(config){
    this.id=config.id;
}
A.prototype.sayHello=function(){
    alert(“function from Class A!”);
}
B=function(config){
    this.name=config.namel;
}
然后让B来继承A:
A=Ext.extend(A,B);(该行有误,多谢log4j兄指出)


正确写法是这样:

B=Ext.extend(B,A);


     但是,通过这种写法你会发现,超类A的属性(id)没有被B继承过来。
因为Ext.extend()函数里面的if(typeof sp == 'object'){…}不成立,在继承之后,子类B仅仅获得了超类的sayHello()方法。

第二种写法(不提供子类自己的构造函数):
C=Ext.extend(A,{});
这样的话子类C可以顺利地获得超类A的id属性和sayHello()方法

第三种写法(在overrides里面提供constructor):
例如overrides被定义成这样:
{
    constructor:function(config){
this.superclass.constructor.call(this.config);
}
}
     必须加一句调用:this.superclass.constructor.call,这句实际上是调用父类的构造器来使子类获得父类里面定义的参数。
但是这么做有一点不是很爽,例如我要自定义一个MyPanel来继承Ext.Panel,如果我想采用第三种写法,自己提供的overrides里面必须有如上的手工调用的语句。如果继承的层次稍微深一点,那么每次继承都要写同一句话,这显然是很不爽快的事情。


二、自己来构造一个extend函数
     继承的实质是什么?
     如果简单来说的话,它可以分两方面:一是从父类获得一些属性;二是从父类获得一些方法,从而达到代码复用的目的。
那么,来考虑如下情况:
有一个Plant类来描述植物,它有一个属性id,有一个方法grow(),那么这个类看起来可能是这样的:
Plant=function(config){
this.id=config.id;
}
Plant.prototype.grow=function(){
alert(“Plant grows…”);
}
     现在有Fruit类来描述水果,显然它继承自Plant类,它增加了一个属性isSweet来描述是不是甜的。
Fruit=function(config){
this.isSweet=config.isSweet;
}
     现在,如果用Ext的extend函数,可以这么写:Fruit=Ext.extend(Fruit,Plant);但是,这么写有个缺点,就是Fruit类并没有把父类Plant的id属性继承下来,而只是继承了父类的grow()方法。
那么,只能被迫采用第三种写法,提供一个overrides,然后在里面加个constructor。这显然不是很爽。我们期望的效果是,子类有自己的构造函数,同时还能把父类的属性和方法都继承下来。那么,我们就可以来尝试做个自己的继承工具。
     想一想JAVA里面的继承,在调用子类自己的构造函数之前,默认会调用一次父类的构造函数。那么,我们借鉴一下Ext.extend,使用闭包的原理,同时增加一点自己的内容:
MyUtil={};
MyUtil.extend=function(){
return function(sb,sp,overrides){
if(typeof sp =='object'){//没有传递子类的构造函数
overrides=sp;
sp=sb;
//继承父类属性
sb=function(){
sp.apply(this,arguments);
};
}else{//如果子类已经有自己定义的构造函数
var cache=sb;//把子类的构造函数先缓存起来
sb=function(){ //重新包装出一个构造函数
sp.apply(this,arguments);//首先调用父类的构造函数 cache.apply(this,arguments);//然后调用自身的构造函数
};
}
//继承父类方法
var sbp=sb.prototype;
var spp=sp.prototype;
A.apply(sbp,spp);
sb.constructor=sb;
A.apply(sb,overrides);
return sb;
}
}();

     好,有了如上的继承工具,就可以完成想要的功能,而且可以完成层次比较深的继承关系了。
     以下是一个完整的测试例子,直接引入到html里面可以看到结果。最低层的D类获得了所有超类的属性和方法。
MyUtil={};

MyUtil.apply=function(des,src,defaults){
if(defaults){
ExtSvg.apply(des,defaults);
}
if(des&&src&&typeof src=='object'){
for(var p in src){
des[p]=src[p];
}
}
return des;
};

MyUtil.extend=function(){
return function(sb,sp,overrides){
if(typeof sp =='object'){//没有传递子类的构造函数
overrides=sp;
sp=sb;
//继承父类属性
sb=function(){
sp.apply(this,arguments);
};
}else{//如果子类已经有自己定义的构造函数
var cache=sb;//把子类的构造函数先缓存起来
sb=function(){ //重新包装出一个构造函数
sp.apply(this,arguments);//首先调用父类的构造函数 cache.apply(this,arguments);//然后调用自身的构造函数
};
}
//继承父类方法
var sbp=sb.prototype;
var spp=sp.prototype;
A.apply(sbp,spp);
sb.constructor=sb;
A.apply(sb,overrides);
return sb;
}
}();

/**
* Class B
*/
B=function(paramObj){
this.id=paramObj.id;
this.meterName=paramObj.meterName;
}
B.prototype.BsayHello=function(){
alert(this.id);
}

/**
* Class C
*/
C=function(paramObj){
this.privateName=paramObj.name;
}
C=MyUtil.extend(C,B);
C.prototype.CsayHello=function(){
alert("This is the msg from Class C!");
}

/**
* Class D
*/
D=function(paramObj){
this.delay=paramObj.delay;
}
D=MyUtil.extend(D,C);
D.prototype.DsayHello=function(){
alert("This is the msg from Class D!");
}

/**
* test functioin
*/

var test=new C({id:'this is the id of class c!',name:'xiaofei',meterName:'meterName',delay:'delayed 3 days!'});
for(var p in test){
alert(p+"-->"+test[p]);
}

三、几句废话
     在通过原型链模拟出继承关系之后,脚本已经可以具备强大的功能,写出来的代码应该比较“面向对象”,而不是散落一地的一堆毫无关系的函数。但是,在实际使 用Ext这个优秀的js框架的时候,笔者发现,很多人(包括笔者自己)写出来的东西仍然是一堆函数。而没有能发挥出“继承”的威力。写出来的JS代码很长 很大,重复的代码非常多。
     鉴于这样的情况,笔者认为,在真正动手写JS之前,需要先好好分析一下一个页面的构成,里面有多少固定的东西,稍微封装一下再来做,情况会好很多。Ext这个类库非常优秀,千万不能把它当烧火棍来用啊!!

你可能感兴趣的:(C++,c,prototype,ext,C#)