- /*
- * Ext JS Library 2.0
- * Copyright(c) 2006-2007, Ext JS, LLC.
- * licensing@extjs.com
- *
- * http://extjs.com/license
- */
- //构建Ext单例对象
- //js中可以直接创建对象,这和java、c++等OO语言中
- //只能定义类,再创建对象是不一样的了
- //这种方式是js中构建单例对象的一个比较好的方式了
- Ext = {version: '2.0' };
- //在浏览器端开发中,window是全局对象
- //下面句子往window这个全局对象中动态注入undefined属性
- //尽管在emac的标准中要求全局对象中必须有个undefined的状态
- //但是当浏览器替换了全局对象时间,undefined这个变量的状态可能
- //就定义了。特别是old browsers....这样的解释有任何问题可以一起留言商讨
- //这样的处理方式只能针对undefined的了。
- // for old browsers
- window["undefined" ] = window[ "undefined" ];
- /**
- * @class Ext
- * Ext core utilities and functions.
- * @singleton
- */
- /**
- * Copies all the properties of config to obj.
- * @param {Object} obj The receiver of the properties
- * @param {Object} config The source of the properties
- * @param {Object} defaults A different object that will also be applied for default values
- * @return {Object} returns obj
- * @member Ext apply
- */
- Ext.apply = function (o, c, defaults){ //从代码的实现过程来看defaults中的属性会被c中属性覆盖,default只有在
- //c中没有定义的时候,才会用default中定义的属性
- if (defaults){
- //显然这里用this也是可以调用到Ext中的apply方法的,但是想想为什么这里不用this呢?就是说下面的句子直接改为
- //this.apply(o.defaults)。
- //下面作者的注释已经说明了问题的所在了。为了在scope(作用域)之外可以友好地调用到该方法,该方法定义
- //在Ext这个全局的单例的对象之中,那么scope就是指Ext内了。那么在Ext之外调用时什么意思呢?不是可以通过
- //Ext.apply直接调用到吗,这有什么问题?
- //这样当然没有问题。不过想想js中函数调用的另外一种方式:Ext.apply.apply或者Ext.apply.call。
- //我想作者指的调用方式,就是call和apply这种scope范围之外的调用方式吧。这样作用域外调用会的话,用this关键字的话
- //问题就来了。如:function Man(){} ,Ext.apply.call(new Man(),new Man(),new Woman());
- //用上“this” reference
- //会抛出个错误说Man中的apply未定义。
- //apply和call的这种调用方式,都会有this问题。如果是Ext这样的单例对象的话,建议都不要this来内部调用,都搞Ext前缀算了。
- //以免引发一些“friendly”的问题。
- // no "this" reference for friendly out of scope calls
- Ext.apply(o, defaults); //这里要开始递归调用Ext.apply的方法了,如果defaults存在的话,递归第一轮就走到下面的代码去了。
- }
- //这里o&&c都还好理解,说明只要在o和c都存在的时候才有必要做某些操作,那么typeof c=='object'又是为了限制什么呢
- //如果不加上这个条件会怎么样?
- //这个问题与typeof能区分出什么东西息息相关,从犀牛中的typeof的解释上看,typeof只能区分对象类型与基本类型。
- //也就是说,如果发现c是基本类型的话,下面的属性拷贝工作就根本不会做了(也不应该做,但是如果真得传递一个1进去,好像也不会出现啥恐怖的事情)。
- if (o && c && typeof c == 'object' ){
- //这个就没啥好说的,c中的属性被全部拷贝到o中了
- for ( var p in c){
- o[p] = c[p];
- }
- }
- return o;
- };
- //这里使用匿名函数来完成Ext这个单例对象中相关属性的设置
- //形如:(function(){})();
- //那么这里使用匿名函数是否是有什么特殊的考虑?
- //尽管这个匿名函数的逻辑可以定义在某个有名的函数,如init_ext()中,然后再加以调用
- //但是能用匿名函数一步到位的事情为啥要分两个步骤呢:)
- //充分利用语言的性质,看来使用匿名函数形成的闭包来做初始化工作也是不错的了。
- (function (){
- var idSeed = 0; //查看下面的Ext.id方法,用来对id递增
- //下面这些策略就是为了判断浏览器的类型了,很常见的一种用法
- //既然Ext是一个cross-browser的框架,那么肯定要知道自己运行的平台是哪种浏览器了... ...
- var ua = navigator.userAgent.toLowerCase();
- //下面是摘自dhtml网页制作完全手册中,对document.caompatMode的描述
- When standards-compliant mode is switched on, Internet Explorer renders the document in compliance with the Cascading Style Sheets (CSS), Level 1 (CSS1) standard. When standards-compliant mode is not switched on,
- // rendering behavior is consistent with previous versions of Internet Explorer.
- var isStrict = document.compatMode == "CSS1Compat" ,
- isOpera = ua.indexOf("opera" ) > -1,
- isSafari = (/webkit|khtml/).test(ua),
- isIE = !isOpera && ua.indexOf("msie" ) > -1,
- isIE7 = !isOpera && ua.indexOf("msie 7" ) > -1,
- isGecko = !isSafari && ua.indexOf("gecko" ) > -1,
- isBorderBox = isIE && !isStrict,
- isWindows = (ua.indexOf("windows" ) != -1 || ua.indexOf( "win32" ) != -1),
- isMac = (ua.indexOf("macintosh" ) != -1 || ua.indexOf( "mac os x" ) != -1),
- isLinux = (ua.indexOf("linux" ) != -1),
- isSecure = window.location.href.toLowerCase().indexOf("https" ) === 0;
- //就是说ie7之前的ie浏览器对背景图像有些默认的处理方式,按作者的注释说,如果不执行这个command的话
- //css 图片会晃动。
- // remove css image flicker
- if (isIE && !isIE7){
- try {
- document.execCommand("BackgroundImageCache" , false , true );
- }catch (e){}
- }
- //来了,在这里将往Ext这个大对象中加入属性了
- Ext.apply(Ext, {
- /**
- * True if the browser is in strict mode
- * @type Boolean
- */
- isStrict : isStrict, //函数开始位置对平台检测的结果用上了...
- /**
- * True if the page is running over SSL
- * @type Boolean
- */
- isSecure : isSecure,
- /**
- * True when the document is fully initialized and ready for action
- * @type Boolean
- */
- isReady : false ,
- /**
- * True to automatically uncache orphaned Ext.Elements periodically (defaults to true)
- * @type Boolean
- */
- enableGarbageCollector : true , //注意看下面的Ext的垃圾回收算法... ...
- /**
- * True to automatically purge event listeners after uncaching an element (defaults to false).
- * Note: this only happens if enableGarbageCollector is true.
- * @type Boolean
- */
- enableListenerCollection:false , //注意Ext中对缓存机制....在缓存元素被删除之后,元素上面的监听器(元素上面可能绑定很多类似事件的监听器)一并会被删除掉
- /**
- * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
- * the IE insecure content warning (defaults to javascript:false).
- * @type String
- */
- SSL_SECURE_URL : "javascript:false" , //这个用在啥地方,很用途还不是很清楚
- /**
- * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images. (Defaults to
- * "http://extjs.com/s.gif" and you should change this to a URL on your server).
- * @type String
- */
- BLANK_IMAGE_URL : "http:/" + "/extjs.com/s.gif" , //空白css背景图片,这个一定要该,否则在内存上部了网的时候,可能会出现图标正在下载的情况//下不到的话,则可能会有叉叉
- /**
- * A reusable empty function
- * @property
- * @type Function
- */
- emptyFn : function (){}, //一个占位符函数,就是用了指导某个函数上... ...prototype框架里面也专门定义了个 空函数 属性
- /**
- * Copies all the properties of config to obj if they don't already exist.
- * @param {Object} obj The receiver of the properties
- * @param {Object} config The source of the properties
- * @return {Object} returns obj
- */
- applyIf : function (o, c){ //注意与Ext.apply方法的区别,该方法只有在属性没有定义的时候才会拷贝c中的属性
- if (o && c){
- for ( var p in c){ //回忆下undefined状态,undefined状态意味着对象属性没有定义,或者某个对象声明却没有赋值
- if ( typeof o[p] == "undefined" ){ o[p] = c[p]; }
- }
- }
- return o;
- },
- /**
- * Applies event listeners to elements by selectors when the document is ready.
- * The event name is specified with an @ suffix.
- <pre><code>
- Ext.addBehaviors({
- // add a listener for click on all anchors in element with id foo
- '#foo a@click' : function(e, t){
- // do something
- },
- // add the same listener to multiple selectors (separated by comma BEFORE the @)
- '#foo a, #bar span.some-class@mouseover' : function(){
- // do something
- }
- });
- </code></pre>
- * @param {Object} obj The list of behaviors to apply
- */
- addBehaviors : function (o){ //似乎是因为使用上DomQuery库,在Ext中似乎有许多地方都使用 css的 selector(选择器)来定位一个dom节点
- if (!Ext.isReady){ //想想使用css定位器来定位对象,看来也挺ok的,元素都定位得到了。
- Ext.onReady(function (){
- Ext.addBehaviors(o);
- });
- return ;
- }
- //这个cache只是用来,做为算法的辅助工具
- //Ext.select毕竟是耗时间的事情,能省则省啊,而且一般情况下,我们调用一次addBehaviors方法只对一个元素增加监听器会比较清楚些。
- var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
- for ( var b in o){
- var parts = b.split( '@' );
- if (parts[1]){ // for Object prototype breakers
- var s = parts[0];
- if (!cache[s]){
- cache[s] = Ext.select(s);
- }
- cache[s].on(parts[1], o[b]); //Element的on方法了
- }
- }
- cache = null ;
- },
- /**
- * Generates unique ids. If the element already has an id, it is unchanged
- * @param {Mixed} el (optional) The element to generate an id for
- * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
- * @return {String} The generated Id.
- */
- id : function (el, prefix){ //产生一个唯一的ID
- prefix = prefix || "ext-gen" ;
- el = Ext.getDom(el);
- var id = prefix + (++idSeed);
- //由于js支持类型转化,所以对象本身可以直接成为条件运算的内容,el是否存在在js中直接用if(el)来判断。
- return el ? (el.id ? el.id : (el.id = id)) : id; //el没id则才弄出id;这个要是弄好点的话,可以在函数的最开始做判断,这样就有可能免掉Ext.getDom(e1)这样的运算了。
- },
- /**
- * Extends one class with another class and optionally overrides members with the passed literal. This class
- * also adds the function "override()" to the class that can be used to override
- * members on an instance.
- * @param {Object} subclass The class inheriting the functionality
- * @param {Object} superclass The class being extended
- * @param {Object} overrides (optional) A literal with members
- * @method extend
- */
- extend : function (){
- //extend是重要的函数了,OO的继承在Ext中靠它了
- //语法上使用上了个闭包
- //函数定义完之后,马上进行调用,并且返回了也是个函数
- //从该函数的实现上看,该函数值针对子类以及父类的prototype操作,难怪Ext要求要在子类的构造函数中进行这样的调用语句
- //Subclass.superclass.constructor.call(this,arguments);显示地拷贝父类中非prototype定义的属性
- //如果非prototype所定义的方法,将不会被overrides中的属性所覆盖.
- // inline overrides
- var io = function (o){
- for ( var m in o){
- this [m] = o[m];
- }
- };
- return function (sb, sp, overrides){
- /**
- (转)
- 1,关于F的用法
- 使用F是为了避免对sb原型对象的操作,联动影响sp的原型对象.
- 2,当typeof sp == "function"时
- sb的原型将被替换,不保留任何原型属性
- sb的superclass指向sp的原型对象
- 3,当typeof sp == "object"时
- sb的原型属性将被保留
- sb的superclass指向自己的原型对象
- 效果略等同于override
- 另:
- 1,apply,applyIf主要用于typeof == "object"时的对象操作
- 2,override,extend主要用于typeof == "function"时的对象原型操作
- **/
- if ( typeof sp == 'object' ){ //如果sp也是对象的话,而不是函数类 (!='function').一般来说sp这里放的是父类的构造函数),那么第三个参数overrides参数相当于被忽略掉
- overrides = sp;
- sp = sb; //sb重新定义了函数
- }
- var F = function (){}, sbp, spp = sp.prototype;
- F.prototype = spp;
- sbp = sb.prototype = new F();
- sbp.constructor=sb;
- sb.superclass=spp;
- if (spp.constructor == Object.prototype.constructor){
- spp.constructor=sp;
- }
- sb.override = function (o){
- Ext.override(sb, o);
- };
- sbp.override = io;
- //覆盖掉子类prototype中的属性
- Ext.override(sb, overrides);
- return sb;
- };
- }(),
- 关于两个参数与三个参数extend方法注释补充。
- /**
- Ext.extend的两个参数的与三个参数的使用方法很不一样。
- 三个参数如:
- Ext.extend(Sub,Super,{})
- 直接改变了Sub的构造函数本身,让Sub的prototype指向
- Super。
- 两个参数如:
- Ext.extend(Sub,{});
- 并不改变Sub本身,从代码中看由于传递进去的Sub引用(引用的拷贝)被
- 替换为新的function,而Sub本身却没有被改变,所以
- Ext.extend(Sub,{});的执行不会改变Sub本身。
- 两个参数的extend的使用时通过,接收其返回才有意义:
- OSub = Ext.extend(Sub,{});
- Ext中也有许多地方用到两个参数的extend,如:
- Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
- readRecords : function(o)
- {
- // do something
- }
- });
- */
Extjs 研究 Ext.extend
最新推荐文章于 2021-10-25 10:50:47 发布