首先声明一下,以下部分内容摘自网上
一、 有了上一篇ExtJs源码结构和ExtJs自带的调试工具后,下面介绍一下ExtJs最核心的部分ext-core
二、 首先看Ext.js文件
- window.undefined = window.undefined;
该段代码是为了兼容不支持window.undefined对象的老版浏览器(估计现在没人用老版浏览器了,呵呵),详细说明可参考
有关window.undefined=window.undefined写法的理解
- Ext = {
- /**
- * The version of the framework
- * @type String
- */
- version : '3.3.1',
- versionDetail : {
- major : 3,
- minor : 3,
- patch : 1
- }
- };
以上代码定义全局变量Ext
- /**
- * ExtJs实现对象继承
- * 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){
- // no "this" reference for friendly out of scope calls
- if(defaults){
- Ext.apply(o, defaults);
- }
- if(o && c && typeof c == 'object'){
- for(var p in c){
- o[p] = c[p];
- }
- }
- return o;
- };
ExtJs核心代码之一,主要实现对象的继承
该方法有两种执行
其一,只传o,c时直接将c上的所有属性/方法拷贝给o后返回;
其二,defaults也传时,会将defaults,c上的所有属性/方法都拷贝给o ,传三个参数时,首先拷贝defaults,然后再拷贝c,这个方法的实现蛮有意思的。
有了该方法后,ExtJs中对象之间的继承就变得容易多了,只要调用该方法,就可以把A对象上的所有方法复制到B对象上。
- /**
- * 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){
- if(o){
- for(var p in c){
- if(!Ext.isDefined(o[p])){
- o[p] = c[p];
- }
- }
- }
- return o;
- },
Ext.apply方法进行复制,它会覆盖子对象中的同名属性或方法的,ExtJs为了避免这种不必要的覆盖有提供了Ext.applyIf函数,该函数可以解决这个问题,在进行属性和方法复制时会判断子对象中是否已存在。
接下来是一个匿名函数,而且该匿名函数在初始化时即运行。执行完后给Ext上扩展了许多实用的属性和方法。
在匿名函数中首先定义了一些局部变量,比如判断浏览器种类、操作系统等。接下来的代码解决了IE6下css背景图不缓存的bug
- // remove css image flicker
- // 解决IE6下css背景图不缓存bug
- if(isIE6){
- try{
- DOC.execCommand("BackgroundImageCache", false, true);
- }catch(e){}
- }
实现原理及说明可参见
接下来就是Ext.apply()的应用了,扩展了许多Ext实用方法和属性
其中Ext.isStrict 并非判断html文档模式为严格模式,而是指标准模式,如<!DOCTYPE HTML>声明会返回true。详细说明可参考用doctype激活浏览器模式 ,国内的秦歌 翻译了该篇文章
- /**
- dom节点id,没有设置ExtJs会默认生成
- * 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){
- el = Ext.getDom(el, true) || {};
- if (!el.id) {
- el.id = (prefix || "ext-gen") + (++idSeed);
- }
- return el.id;
- },
该方法为dom元素生成唯一id,如果该元素id存在则不重新生成。默认id前缀为ext-gen,也可通过传参prefix改变
ECMAScript 5已经发布半年多了,添加了一些新的API方法,如Array的indexOf,forEach等方法,部分新版本浏览器已经支持这些方法来,但我们想为老的浏览器扩展该方法。可能会这样写
- var proto = Array.prototype; if(!proto.indexOf){ proto.indexOf = function(){ // ... } } if(!proto.forEach){ proto.forEach = function(){ // ... } }
上面书写即保证优先使用浏览器原生支持的API方法,不支持的使用自定义实现的。但这里每次都需要判断下Array原型上是否存在该方法。
google closure 实现方式类似使用了三元运算符,每次都要判断下,相对丑陋。网上有一些对google closure的 批评 ,及一些效率低下的 具体分析 ,批评者甚至包括大牛:Dmitry Baranovskiy 。相对来说,Ext.applyif则使的API的扩展很优雅。
这里插入些题外话,关于提高js运行效率,老外写的
http://blogs.sitepoint.com/2009/11/12/google-closure-how-not-to-write-javascript/
From array.js, line 63:
- for (var i = fromIndex; i < arr.length; i++) {
This for loop looks up the .length property of the array (arr) each time through the loop. Simply by setting a variable to store this number at the start of the loop, you can make the loop run much faster:
- for (var i = fromIndex, ii = arr.length; i < ii; i++) {
Google’s developers seem to have figured this trick out later on in the same file. From array.js, line 153:
- var l = arr.length; // must be fixed during loop... see docs ⋮ for (var i = l - 1; i >= 0; --i) {
This loop is better in that it avoids a property lookup each time through the loop, but this particular for loop is so simple that it could be further simplified into a while loop, which will run much faster again:
- var i = arr.length; ⋮ while (i--) {
接下来是Ext.extend方法,该方法也是核心方法之一,整个ext框架继承都是以该方法来扩展的。该方法实现依赖于Ext.override,先看override
- /**
- * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
- * Usage:<pre><code>
- Ext.override(MyClass, {
- newMethod1: function(){
- // etc.
- },
- newMethod2: function(foo){
- // etc.
- }
- });
- </code></pre>
- * @param {Object} origclass The class to override
- * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
- * containing one or more methods.
- * 将对象overrides的所有属性/方法拷贝到类origclass的原型上。
- * 需要注意的是后面的if判断,IE中for in不能遍历对象的Object的toSting等方法,
- * 因此需要特别处理一下。IE9 beta重写对象的内置方法如toString后是可用for in遍历的
- * @method override
- */
- override : function(origclass, overrides){
- if(overrides){
- var p = origclass.prototype;
- Ext.apply(p, overrides);
- if(Ext.isIE && overrides.hasOwnProperty('toString')){
- p.toString = overrides.toString;
- }
- }
- },
该方法实现了将对象overrides的所有属性/方法拷贝到类origclass的原型上。需要注意,IE中for in不能遍历对象的Object的toSting等方法,因此需要特别处理一下。在IE9 beta重写对象的内置方法如toString后是可用for in遍历的,见 for in的缺陷 。
Ext.extend是js继承最经典的实现方式了,参考我之前写的 ExtJs中继承的实现与理解—extend