深入剖析ExtJS 2.2实现及应用连载 版权所有,转载标明出处和作者及版权信息
作者:彭仁夔 QQ:546711211 Blog:http://www.cnblogs.com/jxnuprk或htttp://jljlpch.iteye.com
在javaScript中,面向对象的类是通过函数来模拟的。函数的prototype中的方法和属性可以看作是类的实例方法和属性。函数的的方法和属性可以看作是类的静态(类)方法或属性。对于函数的继承,当然也就是类的继承。
函数的继承和对象的继承差别其实也不是很大。对象的继承是复制到对象的内部,而函数的继承则是把数据复制到函数的原型中。Ext.override方法就是完成这项工作。它只是简单的复制,没有理会继承者与被继承者之间的关系。还有一些问题是值得考虑的,如果没有给定继承者,是不是要构建一个继承者,让其继承被继承者的所有功能呢?继承者是不是也应该有继承的能力呢(为其提供继承的方法)?Ext.extend解决了这样问题,该函数是Ext类库的基石。
Ext.extend函数仅仅当作extend的功能来看待是有点以偏概全的,我们完全可以把看作能继承的构建器。它的功能有点像prototype1.6中类的构建器(Class.create)。在Ext中,我们可以把Ext.extend看作是组件的构建器。如果没有指定子类,它会在继承的同时生成子类并返回。Ext组件树的应用就是完全建立在extend函数的基础之上。而Ext.extend又可以在继承的过程中构建一个新组件并返回。当作组件的构建器一点也不过份。
通过Ext.extend来实现的组件,我们可以通过类的继承链来访问其父类的方法或构建函数,如Office.CompanyPanel.superclass.constructor.call(this, this.meta);在通过extend实现的组件,其在类的关系上已经形成了链条的关系。我们可以通过这个关系访问到其父类。
代码清单3.2 Ext.extend的源码
extend : function(){
//io,oc是采用了闭包函数的特点,减少了函数的变量的定义,只有内部能访问。
var io = function(o){ for(var m in o){this[m] = o[m];} };①
var oc = Object.prototype.constructor;
//sb,sp是函数类型(即类),overrides是对象类型
return function(sb, sp, overrides){ ②
//说明只传入了两个参数。省去sb,sb函数是通过本函数新生成的
if(typeof sp == 'object'){ ③
overrides = sp;
sp = sb;
//如果overrides中含有constructor方法时,它就是sb子类的构造函数。
//否则就新建一个构造函数,传入参数调用其父类的构造函数。
sb = overrides.constructor != oc ?
overrides.constructor : function(){sp.apply(this, arguments);};
}
var F = function(){}, sbp, spp = sp.prototype;
F.prototype = spp;
//采用new F()新建一个含有所有sp.prototype中的功能的对象。
//这里做是为了改变sb.prototype中不会改为sp.prototype
sbp = sb.prototype = new F(); ④
//标识sb的实例对象中的constructor为sb函数。
sbp.constructor=sb;
//通过这里的实现,我们就可以类方法的形式去调用其superclass中的方法。
sb.superclass=spp; ⑤
//改变父类实例对象中的constructor标识,使其指向自身的构建函数
if(spp.constructor == oc){ spp.constructor=sp; } ⑥
//给sb注册一个类方法override.
sb.override = function(o){Ext.override(sb, o); };
//sb实例对象中override方法
sbp.override = io; ⑦
//把overrides中的方法拷到sb的prototype中,使实例拥有该方法
Ext.override(sb, overrides); ⑧
//为子类加上一个类方法:extend
sb.extend = function(o){Ext.extend(sb, o);}; ⑨
return sb;
};
}() ⑩
在上面代码中⑩,我们可以发现这个函数是立即运行的函数。也就是说Ext.extend实际上是②处的函数。那么它为什么要这样做呢?完全可以把①处的两个变量放在②处的函数内部。
因为①处相对每个继承的应用,它们都是不变的。放在函数内部的话,那次每次extend,都要生成这两个变量,用完之后销毁,影响性能。也可以把它们放在Ext的命名变量中,这样做的不好之处在于外部可以引用这两个变量,而我们想这两个变量只能在Ext.extend的内部函数中引用。这里的用法就是采用了函数的闭包特性。提高了效率,又保证其变量的私有性。
上面代码的③是对省略了子类参数的处理。在这种情况下,Ext.extend就要构建子类。如果在构建的对象参数指定了构建这个子类的函数就采用这个函数做为子类的构建器。如果没有的函数,就采用默认的处理,它的默认的处理是把参数传入其父类的构建函数中并运行它。
④处是实现子类原型继承父类原型中的数据。⑤实现了类链的形式。④处第二句和⑥处是指定子类和父类原型的constructor方法,让其指自身的构建函数。⑥处第二句及⑦和⑨处分别为子类或其原型增加override或extend的函数功能。⑧处就是把overrides中的函数或属性全都复制到子类的原型中。
使用Ext.extend是很简单的,对于不需要在构建方法中直接处理一些功能话,我们完全可能通过如下的方法来生成一个即有方法又有属性的继承的类:
var myclass=Ext.extend(spclass,{/ 一些增加方法和属性});// constructor
在Ext的组件中,子类的构建方法中实现的功能一般都在Compoent类中的模板方法initComponent中实现。也就是说一般都是采用上面方面来生成继承的子类。
对于采用子类的自实现的构建方法,相对来说是有点麻烦,如下:
var myclass=function(config){
.. .. ..
myclass.superclass.constructor.call(this, this.meta);//这里是把参数传到父类中构建方法中
… …
}
Ext.extend(myclass,supclass,{//一些增加的方法或属性});
有的时候,还是要可能要采用这种方法来进行继承的,特别是那些不是组件的继承方式,又要构建方法中自定义实现自有的功能。Ext.extend这两种应用,我们在办公系统的扩展组件都会用到。在第二章的leftMenu组件中,我们就是通过它第二种应用的方法来实现其组件继承于Panel组件。
javaEye的blog发布实在是很垃圾。从word贴的话,经常出这样那样的错误!!!!不改进的话,也许很多人会选择其它的blog。