- 浏览: 541243 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (339)
- JavaBase (27)
- J2EE (70)
- Database (22)
- Spring (3)
- struts1.x (6)
- struts2.x (16)
- Hibernate (10)
- IBatis (4)
- DWR (1)
- SSH (5)
- Oracle (31)
- HTML (12)
- javascript (11)
- Thinking (3)
- Workflow (5)
- Live (13)
- Linux (23)
- ExtJS (35)
- flex (10)
- php (3)
- Ant (10)
- ps (1)
- work (2)
- Test (1)
- Regular Expressions (2)
- HTTPServer (2)
- 方言 (1)
- 生活 (2)
- Sybase PowerDesigner (0)
最新评论
-
mikey_5:
非常感谢楼主的分享,<parameter propert ...
Check the output parameters (register output parameters failed) IN Ibatis -
影子_890314:
我现在也有这个错误,求解!
Check the output parameters (register output parameters failed) IN Ibatis -
358135071:
学习了,感谢分享!
使用hibernate 代替 mysql 中 limit 進行分頁 -
wjpiao:
你下面的“正确的映射”里面不是还是有number类型吗?
Check the output parameters (register output parameters failed) IN Ibatis -
zh_s_z:
很有用!弄一份吧!
Oracle数据库分区表操作方法
第一章 必须理解Ext.extend 函 数
显然了,从函数名就可以看出来,这个函数是整个Ext 类 库的基石,之一。
笔者初看这个函数,感觉比较迷糊,只知道它完成了继承的功能,但是里面到底做了什么操作,并不太好理 解。
网络上有很多帖子和文章来解析这个函数,但笔者感觉并不是很到位。不知道是因为这些帖子的作者没有能完 全理解这个函数还是因为表达得不够清晰。
下面笔者就自己的理解来分析一下这个函数。
必须的 前置概念有三个:prototype 、constructor 、 “闭包”
没有这 三个概念的请务必先看第1 、2 、3 段代码,很了解的直接看第4 段代码就可以了。
1 、prototype
RectAngle=function (width,height){
this.width=width;
this.height=height;
}
RectAngle.prototype.area=function(){
return this.width*this.height;
}
这段代码似曾相识吧?来自《JavaScript 权威指 南》。功能很简单的啦,定义个“矩形”的构造函数,有长和宽两个参数。
然后在RectAngle 的prototype 里面增加一个计算面积的函数area.
这样每次在var rect=new RectAngle() 的时候,就可以对rect 对象调用area() 函数了,因为rect 对象从RectAngle 的prototype 里面继承了area() 函数。
这就是“JavaScript 基于原型继承”的简单理解。
2 、constructor
根据《JavaScript 权威指南》上面的解释,每个函数 都有一个prototype 属性,构造函数也是函数,所以也有prototype 属性。prototype 属性在定义 函数的时候会自动创建并初始化. 也就是说, 在 写下RectAngle=function(widht,height){//...} 的时候,RectAngle 的prototype 属性就已经 被创建了, 这个时候prototype 里面 只有一个属性, 它就是constructor( 构 造器), 这个constructor 指回了RectAngle 函数本身。这样就形成了一个圈一样的链条, 可 以实验一下这种调用:
RectAngle.prototype.constructor.prototype.constructor... 这个调用是比较变态的咯,如果你能看懂,你肯定琢磨过这个问 题,呵呵。笔者也是琢磨了比较长的时间才明白其中的含义的。
当然,不明白这种变态写法也没关系的,毕竟每个哪个变态的人会在实际应用的时候写这种东西。
言归正传,对于每个RectAngle 的实例来说, 例如var rect=new RectAngle(10,10) ; rect.prototype 会指向构造函数RectAngle 的prototype ,也就是说所有的实例都会共享同一份RectAngle.prototype ,
如此,就不需要分配那么多内存给每个实例来存储prototype 属 性了。
3 、“闭 包”( 代码来自《JavaScript 权威 指南》) :
RectAngle=function(width,height){
this.getWidth=function(){return width};
this.getHeight=function(){return height};
}
RectAngle.prototype.area=function(){
return this.getWidth()*this.getHeight();
}
发现了吧? 这段代码和第1 段的构造函数是不同的. 从RectAngle.prototype.area 这个函数也可以看出来,除了RectAngle 构造函数内部,外部函数无法直接访问RectAngle 的width 和height 属性,只能通过执行getWidth() 和getHeight() 方法来 获得这两个属性的值。
《指南》上面说,第一个发现这种写法的人是Douglas Crockford ,呵呵,真是个变态的家伙,这都能想出来!无语啊,人和人是有差距的。(笔者的名言)
有了这种写法,就可以动态构建出功能强大的代码了,这种写法的用处是比较多的,例如像缓存调用变量、改变命名空间、 定义私有属性等。依次来解释一下这三个用处:
⑴定义私有属性:从上面的代码可以看出来,外部函数是没有办法直接引用width 和height 这两个属性的,比如var rect=new RectAngle(widht,height);rect.weidth??
这么写就不行了。所以,通过RectAngle 构造器中this.getWidth() 方法就模拟出了一个私有的变量( 因 为JavaScript 没有private 这 个说法,所以只能叫模拟哦) 。
⑵改变命名空间:
例如把上面的代码写成这样:
RectAngle=function(width,height){
getWidth:function(){
var haha=function(){
return width;
}
return haha;
},
getHeight:function(){
var haha=function(){
return height;
}
return haha;
}
}
同样是可以运行的,看出来没有,两个get 函数里面实际上用 了同样名称的方法haha() ,但是没有关系,它们的命名空间是不同的,一个处于getWidth 的作用域,一个处于getHeight 的 作用域。当然在外部调用getWidth() 方法的时候,实际运行的是里面对应的haha() 方法。
⑶缓存变量:
与Java 或者C++ 的 作用域概念类似,一个方法中局部变量(方法的参数也可以看成是局部变量的一种),在方法运行完之后就会实效并释放内存。
例如var rect=new RectAngle(width,height); 按理说,在构造函数执行完毕之后,width 和height 这两个变量就应该释放内存了,但是通过类似这种this.getWidth=function(){return width} 的定义,width 和height 变 量并不释放内存,否则在外部调用getWidht() 的时候,就无法返回对应对象的width 值了。
(“闭包”是稍微复杂的概念,在很多的脚本语言里面都有这个特性,JAVA 中 目前是没有这个概念,据说JAVA7 将会添加“闭包”特性。但是笔者认为,作为一种重量级的语言, 并不是什么特性都要有,像“闭包”这样的东西,在重量级语言里面,稍有不慎“内存泄露”起来是so easy 的! 如果写得再变态一点,很多局部变量都可以“逃出作用域”,变成内存孤岛(没有函数可以释放它,只能看着它干瞪眼)。
4 、好 了,有了上面的简单解释,可以来分析Ext 的extend 这 个函数了。
首先还是把《指南》里面的继承的例子说一下,以便于理解(你很熟悉?跳过吧。)
RectAngle=function(w,h){
this.w=w;
this.h=h;
}
RectAngle.prototype.area=function(){
return this.w*this.h;
}
写个子类来继承RectAngle ,这个子类叫做有颜色的矩 形ColoredRectAngle ,多一个color 属 性
ColoredRectAngle=function(color,w,h){
// 首先调用父类的构造函数来拷贝w 和h 属性,这样的话,ColoredRectAngle 也 就有了w 和h 两个属性
// 为什么不直接this.w=w;this.h=h? 倒,这样 的话,你还用继承干嘛呀?
RectAngle.call(this,w,h);
this.c=color;
}
上面已经把w 和h 属 性拷贝到子类中来了,父类的prototype 里面还有个area 方 法也得想办法拷贝进来,注意了,这是精彩的部分,不能错过哦。
ColoredRectAngle.prototype=new RectAngle();// 这个写 法其实包含了很多内容哦,我们把它拆开来写会更好理解
var rect=new RectAngle();
ColoredRectAngle.prototype=rect;// 怎么样,含义是一样的吧?
好,开始分析这两句话。rect 是RectAngle 的实例(废话,它是由RectAngle 构 造函数构造出来的,当然是它的实例了!),但是
在构造rect 的时候,没有传参数给它,这样的话在rect 这个对象里面w 和h 这两个属性就是null( 显然必须的) 。
既然rect 是RectAngle 的 实例,那么它的prototype 会指向RectAngle.prototype , 所以rect 对象会拥有area() 方法。
另外,rect.prototype.constructor 指 向的是RectAngle 这个构造函数(显然必须的)。
好,现在ColoredRectAngle.prototype=rect , 这一操作有三个问题,第一,rect 的w 和h 被放到ColoredRectAngle.prototype 里 面来了,第二,rect.prototype.area() 这个方法也到了ColoredRectAngle.prototype 里面了,当然,完整的访问area() 方法路径应该是ColoredRectAngle.prototype.prototype.area() , 但是因为JavaScript 的自动查找机制,放在prototype 里 面的属性会被自动找出来(加入从对象的直接属性里面找不到的话。)这样就没有必要写完整的访问路径了,直接写ColoredRectAngle.area() 就 可以找到area() 了,看上去就好像ColoredRectAngle 也 拥有了area() 方法。
值得注意的一点是,在执行RectAngle.call(this,w,h); 这 一步的时候我们已经把w 和h 两个属性拷贝到ColoredRectAngle 里面了,这里我们不再需要rect 里 面这两个值为null 的w 和h ,
所以,直接把它们删除了事,免得浪费内存。
Delete ColoredRectAngle.prototype.w;
delete ColoredRectAngle.prototype.h;
OK ,到了这一步,看起来模拟继承的操作就算大功告成了,父类RectAngle 的w 和h 属性通过RectAngle.call(this,w,h) 拷 贝进来了, 父类prototype 里面的方 法也拷贝进来了,没用的废物(rect 里面,也就是ColoredRectAngle.prototype 里 面,值为null 的w 和h) 也剔除掉了。
看上去世界一片和谐。但是... 还有一个暗藏的问题,请看: 第三:这个时候ColoredRectAngle 类的constructor 指 向错了。
本来,如果没有ColoredRectAngle.prototype=rect 这 步操作,ColoredRectAngle.prototype 就是JavaScript 自动创建出来的那个prototype , 这个prototype 有个constructor , 指向了ColoredRectAngle 构造函数自己.
但是,现在ColoredRectAngle.prototype=rect , 如果现在来访问ColoredRectAngle.prototype.constructor , 那么,根据自动查找机制,会找到rect.prototype.constructor, 但这个constructor 指向的是父类RectAngle 构 造函数,这个就不符合prototype 的游戏规则了。因为,如果此时
var coloredRectAngle=new ColoredRectAngle('red',10,10) alert(coloredRectAngle.constructor);
得到的是父亲RectAngle 的构造函数,从 面向对象的观点看,这个结果是可以理解的,毕竟,子类对象也可以看成是父类对象。
但是,这样的话对于ColoredRectAngle 的实例 来说,就不能确切地知道它的constructor 是ColoredRectAngle 了。
所以,需要手动地把ColoredRectAngle.prototype.constructor 设 置回来。于是有了这一步:ColoredRectAngle.prototype.constructor=ColoredRectAngle.
OK ,看完以上内容,如果你的意识仍然清醒,那就恭喜你了。否则,再仔细看看吧。
正式开始分析Ext.js 里面Ext 这个全局对象的extend 方法。
完整的代码清单如下:
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.js 这个文件 被浏览器加载的时候最外层的无参function 就被执行。这个无参的function 返回了一个有三个参数的function(sb,sp.overrides) 。 还记得上面的“闭包”吗?这种使用方式还是相当有创意的,Ext 库里面存在大量类似的闭包写法。
var io = function(o){
for(var m in o){
this[m] = o[m];
}
};
这一段就不用解释了,是一个用来拷贝属性的普通函数。
var oc = Object.prototype.constructor; 这句定义了一个变量oc , 它的值是Object 这个根类的constructor , 大家可以把它alert 出来看,
它是这样的
function Object(){
[native code]
}
显然,JavaScript 类库并不希望我们看到这个函数里 面的实现,但是我们知道alert 出来的这个东西就是JavaScript 根 类Object 的构造函数。
来分析这个带有三个参数的闭包函数,
if(typeof sp == 'object'){
overrides = sp;
sp = sb;
sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
}
单是这个if 判断当时就让笔者郁闷了好久,呵呵,人和人真的 是有差距的啊!
if(typeof sp == 'object') 这个判断是干嘛的呢?呵呵,它是用来判断你传递进来参数的个数 的。例如Ext.Panel = Ext.extend(Ext.Container, {...});
Ext 类库里面基本都是传两个参数给extend 方法,此时,这个if 判断就要起作用啦。还不明白?硬是要说破啊。因为如果只传两个参数的话,在function(sb,sp,overrides) 看来
第二个参数sp 不就是个“object ”麽?
sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
这一句用来决定子类使用什么形式的构造函数,如果overrides 里 面有个constructor 属性,就用overrides 的constructor 当作子类的构造函数。否则,创建个新的function 出 来,里面包含一句话,就是"sp.apply(this, arguments);" ,这个又是闭包的一个应用哦,在退出extend 方法之后 并没有释放局部变量sp 的内存空间。
这样的话,每次new 一 个子类的时候,第一句执行的就是sp.apply(this,arguments); 这个方法与 《指南》里面RectAngle.call(this,w,h) 完成的功能是一样的。就是把arguments 全部拷贝到子类中去。
好了,属性拷贝完成之后就要拷贝父类prototype 里面的方法了。来看看Ext 又有什么 精彩的写法:
var F = function(){}, sbp, spp = sp.prototype;
F.prototype = spp;
sbp = sb.prototype = new F();
sbp.constructor=sb;
这几句要连起来看哦。
按照前面《指南》里面的写法的话,应该是这样的:
第一步:把子类的prototype 赋值为父类的实例对象。sbp=sb.prototype=new sp();
第二步:删除不要的废属性,因为前面的if 判断里面sp.apply(this,arguments) 已经完成了属性的拷贝。
第三步:把constructor 重新手动指回来。sbp.constructor=sb
发现没有?如果采用《指南》里面的写法,必须要有第二步,把不要的属性都删除掉( 不删会怎样?一个是可能会存在属性覆盖的问题,另外就是内存浪费了,当new 出 很多对象来的时候,这种浪费就很可观了哦!) 。如果属性很多,岂不要写很多delete ?而且要一个一个去核对一下超类里面的属性名称,显然Ext 的 作者并不希望这么做。于是有了这几句精彩的var F=function(){} ,定义一个空函 数,里面没有属性。然后F.prototype=sp.prototype 再然后sbp=new F() 这么做的话,就把F.prototype 也 就是sp.prototype 里面的东西拷贝到sb.prototype 里 面了,同时,因为F 是个没有任何属性的函数,所以不需要再delete 任 何东西了。这句真的很精彩哦!
这时候sb.prototype.constructor 是F() ,所以再来一句sbp.constructor=sb 。 这样的话就完美地完成了对父类prototype 的拷贝,而又没有把不要的属性拷进来。
到了这里,关健的两步操作:属性拷贝、方法拷贝(prototype 里 面的) 都已经完成。
后面的代码就比较简单了,不再解释。
看完这篇文章你应该能理解这个核心的extend 函数到底完 成了什么操作了,如果还是不明白,我不得不承认,那还是我的错,那么请联系我吧QQ :253445528 ,注明“Ext 源码分析”。说明:在5 ×8 小时的上班时间不解答问题。
这篇文章耗费笔者近三个小时的时间,请尊重原创,转载请注明出处,谢谢。
发表评论
-
纵向Tab ---ext
2010-09-28 16:02 1242net address: http://carina. ... -
js code compress
2010-06-11 01:22 997文章转自: http://www.rainway.org/20 ... -
Ext.data.Store
2010-04-16 21:26 1454原文: http://www.9iext.cn/thr ... -
ExtJs 确认密码验证的两种实现
2010-03-17 16:36 5024实现1: ************************* ... -
extjs换肤
2010-02-26 14:15 1233extjs换肤 http://www.javachen ... -
ext 教程
2010-01-29 17:05 1002关于Ext 扩展比较好的文章: http:// ... -
demo
2010-01-26 20:11 1210一、下载extjs 1、从http://www.extj ... -
你的水平 字段没超出所以没 滚动条!
2009-12-16 21:36 1095你的水平 字段没超出所以没 滚动条! 你试下吧 colu ... -
在EXT中使用FCKEditor编辑器例子
2009-12-15 16:47 1238... -
js oo
2009-12-15 10:22 854var RectAngle = function(width, ... -
costom extend
2009-12-15 09:06 932//自定義繼承 ---------------------- ... -
JS中的 prototype的含义
2009-12-14 22:02 1782搜了两 个认为好的讲解 Prototype 属性的 ... -
想起温习一下JS中的this apply call arguments
2009-12-14 21:03 1186很多时候讲到语言入门,大家会认为就是要了 ... -
阅读 Ext 学习Javascript(一)Core/Ext.js
2009-12-14 20:46 956从Library的角度 ... -
阅读Ext学习Js(二)---extend从继承说起
2009-12-14 20:45 1085一般的,如果我们定义一个类,会定义一个function对象,然 ... -
Extjs 研究: js基础
2009-12-14 20:33 10761.我们写的变量 ,函 ... -
ExtJS 入门之一 类与继承
2009-12-14 20:08 805在项目中使用ExtJS已经 ... -
Ext表單中一行多列的布局
2009-12-07 08:01 3831var simpleForm = new Ext.Form ... -
extend Ext component demo
2009-12-06 14:01 882extjs的Ext.extend的使用样例(Ext继承) ... -
使用Ext.extend的几点小结
2009-12-06 13:51 14291. TestExtend3 = Ext.extend(Ex ...
相关推荐
这篇博客文章可能是关于如何在Ext Designer中利用`extend`来设计和自定义UI组件的教程。 首先,我们要理解`extend`在Ext JS中的工作原理。`extend`关键字用于声明一个类是另一个类的子类。这在JavaScript中实现了类...
这里,我们聚焦于`ext`继承,通常指的是JavaScript中的`extend`方法,这是一种实现继承的方式。在JavaScript中,由于语言本身没有内置的类机制,所以开发者通过函数和原型链来模拟类的概念。 `extend`方法通常被...
在`ext-extend.js`这个文件中,可能包含了对`Ext.extend()`的进一步实现和扩展,或者展示了如何在实际项目中重写`Ext`库的方法。通常,这样的代码示例会包含具体的类定义、方法重写以及如何在应用中使用这些自定义类...
EXT JS中的“extend”关键字是实现继承的关键。当你创建一个新的类并声明它`extend`另一个类时,新类将自动获取父类的所有属性和方法。这使得我们可以基于已有的基础类构建更复杂的组件或功能,无需从头开始编写代码...
例如,`Ext.extend(MyClass, Ext.Panel, {myMethod: function() {...}})`创建了一个新类MyClass,它继承自Ext.Panel,并添加了一个名为myMethod的方法。 - `Ext.apply()`: 这个静态方法用于合并对象的属性,通常...
implementation(name: 'android-extend-release', ext: 'aar') } ``` 3. 最后,执行 `gradlew build` 或者在 Android Studio 中同步项目,使库被正确地引入到项目中。 总之,这个压缩包提供了一个名为 "android-...
Leangle.form.combo.ColorComboBox = Ext.extend(Leangle.form.BaseComboBox, { // ComboBox configurations store: new Ext.data.JsonStore({ // store configurations }) }); ``` 在这种情况下,尝试使用`Ext...
"ext多选下拉列表的全选功能实现"这个主题聚焦于一个特定的UI组件——ExtJS库中的MultiComboBox,这是一种允许用户多选的下拉列表控件。在实际应用中,全选功能常常被用来快速选择所有选项,极大地提高了用户的操作...
在ExtJS中,`Ext.extend()` 是一个核心的函数,用于实现类之间的继承机制。它允许你创建新的类(子类),这些类将继承另一个类(父类)的属性和方法。这个功能对于构建复杂的JavaScript应用程序至关重要,因为它提供...
然而,`Ext`库提供了一个更优雅、更易于理解和维护的方式来处理继承,这包括`Ext.extend()`方法和`Ext.create()`函数。 ### `Ext.extend()` `Ext.extend()`是`Ext`库中用于创建子类的核心方法。它接受三个参数:...
EXT测试小样例通常指的是基于EXT JS框架进行的软件测试示例。EXT JS是一个用于构建富客户端Web应用程序的JavaScript库,特别适用于创建数据驱动、交互性强的用户界面。EXT Grid是EXT JS中的一个核心组件,它提供了一...
Ext.extend(Ext.grid.Column, { renderer: function(value, meta, record, rowIndex, colIndex, store) { if (value) { return '图片" />'; } else { return ''; } } }); var grid = new Ext.grid....
"第一章 必须理解Ext_extend函数.mht"和"EXT JS组件事件.mht"可能深入讨论了EXT的扩展机制和组件事件处理,是EXT开发的重要基础。 "EXT 中文手册.pdf"则是EXT的官方中文文档,是学习EXT API的权威参考资料,包含...
Mis.Ext.CrudPanel = Ext.extend(Ext.Panel, { // ... 具体实现细节省略 }); ``` 要使用这个CRUD面板,需要进一步继承并实现特定的需求,比如文中给出的例子是创建一个污水厂管理面板: ```javascript ...
使用`extend`关键字来指定父类,如`Ext.extend('SubClass', 'SuperClass')`。 7. **类实例方法重写**:在子类中,可以重写父类的实例方法,以实现不同的功能。在Ext中,你可以直接在子类中定义相同的方法名来实现...
使用 `Ext.extend` 可以方便地扩展现有的Ext组件类,创建新的组件类型。例如,创建一个搜索面板组件: ```javascript SearchPanel = Ext.extend(Ext.Panel, { constructor: function () { this.addEvents('...
extend: 'Ext.panel.Panel', requires: ['MyApp.util.MyUtil'], // 延迟加载 MyUtil 工具类 // ... }); ``` 当创建 `MyApp.view.MyPanel` 实例时,`MyApp.util.MyUtil` 将自动加载。 4. **路径映射** `paths...
EXTJS中的继承是通过`Ext.extend()`或`Ext.createByAlias()`实现的。继承允许子类重写或扩展父类的方法和属性。例如,我们可以创建一个新的按钮类,继承自EXTJS的`Ext.button.Button`: ```javascript MyButton = ...
- **Ext JS的类系统基于MVC模式,使用EXT.extend方法实现类的继承**,这使得代码复用和模块化成为可能。 - **配置对象(Configurations)**: 大多数类允许通过配置对象进行初始化,简化了组件的创建过程。 3. **...