- 浏览: 527729 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (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 1200net address: http://carina. ... -
js code compress
2010-06-11 01:22 952文章转自: http://www.rainway.org/20 ... -
Ext.data.Store
2010-04-16 21:26 1402原文: http://www.9iext.cn/thr ... -
ExtJs 确认密码验证的两种实现
2010-03-17 16:36 4969实现1: ************************* ... -
extjs换肤
2010-02-26 14:15 1197extjs换肤 http://www.javachen ... -
ext 教程
2010-01-29 17:05 952关于Ext 扩展比较好的文章: http:// ... -
demo
2010-01-26 20:11 1176一、下载extjs 1、从http://www.extj ... -
你的水平 字段没超出所以没 滚动条!
2009-12-16 21:36 1043你的水平 字段没超出所以没 滚动条! 你试下吧 colu ... -
在EXT中使用FCKEditor编辑器例子
2009-12-15 16:47 1190... -
js oo
2009-12-15 10:22 815var RectAngle = function(width, ... -
costom extend
2009-12-15 09:06 872//自定義繼承 ---------------------- ... -
JS中的 prototype的含义
2009-12-14 22:02 1736搜了两 个认为好的讲解 Prototype 属性的 ... -
想起温习一下JS中的this apply call arguments
2009-12-14 21:03 1132很多时候讲到语言入门,大家会认为就是要了 ... -
阅读 Ext 学习Javascript(一)Core/Ext.js
2009-12-14 20:46 920从Library的角度 ... -
阅读Ext学习Js(二)---extend从继承说起
2009-12-14 20:45 1050一般的,如果我们定义一个类,会定义一个function对象,然 ... -
Extjs 研究: js基础
2009-12-14 20:33 10471.我们写的变量 ,函 ... -
ExtJS 入门之一 类与继承
2009-12-14 20:08 768在项目中使用ExtJS已经 ... -
Ext表單中一行多列的布局
2009-12-07 08:01 3780var simpleForm = new Ext.Form ... -
extend Ext component demo
2009-12-06 14:01 849extjs的Ext.extend的使用样例(Ext继承) ... -
使用Ext.extend的几点小结
2009-12-06 13:51 13721. TestExtend3 = Ext.extend(Ex ...
相关推荐
ext 的详细解读,以及实际应用,与大家一起分享。
/* *CRUD面板基类 */ //继承EXT的Panel,创建CRUD面板 Mis.Ext.CrudPanel=Ext.extend(Ext.Panel,{……}); //限于篇幅就不列出全部代码 EXT里的继承用的是Ext.extend(组件名,{实现代码}); 要使用这个CRUD面板,...
NULL 博文链接:https://wmch.iteye.com/blog/974219
NULL 博文链接:https://lggege.iteye.com/blog/602587
EXT测试小样例EXT测试小样例EXT测试小样例EXT测试小样例EXT测试小样例EXT测试小样例EXT测试小样例
MyGridView=Ext.extend(Ext.grid.GridView,{ renderHeaders : function(){ var cm = this.cm, ts = this.templates; var ct = ts.hcell,ct2=ts.mhcell; var cb = [], sb = [], p = {},mcb=[]; for(var i = 0...
9.1 利用Ext.extend实现继承 254 9.2 与Ext扩展相关的预备知识 256 9.2.1 定义命名空间 256 9.2.2 重写构造函数 257 9.2.3 继承组件的一些准备 257 9.2.4 常用的辅助函数 258 9.2.5 使用xtype 258 9.3 实现一个功能...
Ext JS in Action is a comprehensive guide to Ext JS. By following its rich examples, patterns, and best practices, you'll ...Extend the framework and write plug-ins Watch the author develop an Ext JS app
ext继承重写,达到了很高的水平。使用了很多方式,等等。
extend: 'Ext.app.Controller', stores: ['GoodsStore'],//声明该控制层要用到的store models: ['GoodsModel'],//声明该控制层要用到的model views: ['goods.GoodsListView','goods.GoodsWinView'],//声明该控制...
4.1.3 不推荐的extend方法 / 92 4.1.4 数据及其类型检测 / 95 4.1.5 其他的基础方法 / 99 4.2 为框架顺利运行提供支持 / 107 4.2.1 平台检测工具:ext.is / 107 4.2.2 当前运行环境检测工具:ext.supports / ...
前面我们扩展了bind方法和ready函数,这次我要讲一下$.fn.extend 和$.extend函数。 其他的不多说,直接切入主题吧! 先来看看这两个函数的区别: $.fn.extend是为查询的节点对象扩展方法,是基于$的原型扩展的方法...
EXT 结合struts2,用json方式与ACTION通信,非常经典的入门例子! 里面对ext.extend用的很好!
Most configuration options are inherited from Ext.Window (see ExtJs docs). The added ones are: url - the url where to post uploaded files. base_params - additional post params (default to {}). ...
Ext.extend(Ext.form.CKEditor, Ext.form.TextArea, { onRender : function(ct, position){ if(!this.el){ this.defaultAutoCreate = { tag: "textarea", autocomplete: "off" }; } Ext.form.TextArea....
关于这个原因有很多种,我只说下我遇到的 我这样 写Store来复用的 代码如下: DocStore = Ext.extend(Ext.data.Store,{ initComponent:function(){ this.proxy = new Ext.data.HttpProxy({url:this.url}); this....
jq中的extend在面试中经常会被问道,今天我总结一个下有关于extend的用法三种进行对比,可能不全,希望大家指点, 用法一: $.extend({}) ,为jQuery类添加方法,可以理解为扩展静态方法 用法二:$.fn.extend({}) ...
Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,dest是要整合的空间可以使{} 或者不写 src是一个JSON表达式表示的javascript对象…. 因此里面可以添加方法属性等等… 我么通过不同...
本文实例讲述了Vue.extend实现挂载到实例上的方法。分享给大家供大家参考,具体如下: 这里主要是做个笔记 根据官网的说法,Vue.extend:是使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。 ...
最近在自学Python语言,看到向列表增加更多数据时被append(),extend(),insert()方法绕晕了。 append 和extend都只需要一个参数,并且自动添加到数组末尾,如果需要添加多个,可用数组嵌套,但是 append是将...