ExtJs 源码笔记------Ext.js

ExtJs 源码笔记------Ext.js

最近准备系统的学习一下Ext的源码,SO,话不多说,从第一篇开始。

首先,先看一下Ext.js这个文件的代码结构:

var Ext = Ext || {}; // 定义全局变量
Ext._startTime = new Date().getTime();

(function(){
     
     // 定义一些局部变量
     var ......

     // 核心
     Ext.apply = function(){......};

    // 初始化 Ext 的一些属性函数
    Ext.apply(Ext, {......});
    
}());

// 全局闭包
Ext.globalEval  = ......

代码的结构不难,但是仔细看下来,有些细节的地方还是很值得回味一番。下面具体分析一下我对源码的理解,水平有限,不足之处还望各位看官指正。

1. 定义局部变量

  var global = this,
        objectPrototype = Object.prototype,
        toString = objectPrototype.toString,
        enumerables = true,
        enumerablesTest = {toString: 1},
        emptyFn = function () {},
        ......

    for (i in enumerablesTest) {
        enumerables = null;
    }
// 看到这里的时候,有点疑惑,enumerables 不是肯定会被置为 null 吗 // 下面为什么还需要判断enunerables? 有蹊跷..... // 返回去再看一下 enumerablesTest,里面只有一个属性 toString, 为啥偏偏是这样的一个属性?? 嗯!想起来了,在IE6下,对象中的toString属性,不能通过
hasOwnProperty或for...in迭代得到
// So,这里其实就是为了兼容IE6用的。bingo! if (enumerables) { enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; }

2.Ext.apply

Ext.apply = function(object, config, defaults) {
        if (defaults) {
            Ext.apply(object, defaults);
        }

        if (object && config && typeof config === 'object') {
            var i, j, k;
            
            // 拷贝对象,不过这里只是实现了浅拷贝,即如果一个对象中的属性也是一个Object或者Array,会有引用的问题。
            for (i in config) {
                object[i] = config[i];
            }
          
            // 兼容IE6
            if (enumerables) {
                for (j = enumerables.length; j--;) {
                    k = enumerables[j];
                    if (config.hasOwnProperty(k)) {
                        object[k] = config[k];
                    }
                }
            }
        }

        return object;
    };
    

Ext.apply没有实现深层拷贝对象的功能,要想了解更多的关于Ext中拷贝对象的内容,可以狠狠的点击这里

3.初始化 Ext 对象

3.1

Ext.apply(Ext, {

       ......
        // 拷贝对象,不去覆盖object中的原始属性。
        applyIf: function(object, config) {
            var property;

            if (object) {
                for (property in config) {
                    if (object[property] === undefined) {
                        object[property] = config[property];
                    }
                }
            }

            return object;
        },

        // array 和 object 的数据迭代
        iterate: function(object, fn, scope) {
            if (Ext.isEmpty(object)) {
                return;
            }

            if (scope === undefined) {
                scope = object;
            }

            // 可以看到这里真正起作用的是 Ext.Array.each 和 Ext.Object.each方法。

            if (Ext.isIterable(object)) {
                Ext.Array.each.call(Ext.Array, object, fn, scope);
            }
            else {
                Ext.Object.each.call(Ext.Object, object, fn, scope);
            }
            // 复习一下 function.call的用法,第一个参数指定的函数运行过程中所指代的 this。
        }
    });

3.2

 Ext.apply(Ext, {

        // 在4.0或以上版本中这个方法已经被Ext.define取代
        extend: ......
    
        override: function (target, overrides) {
            if (target.$isClass) {
                // 若target是一个 class,则调用该类自己的override方法
                target.override(overrides);
            } else if (typeof target == 'function') {
                 // 若target是一个 function, 则将overrides拷贝到原型链上
                Ext.apply(target.prototype, overrides);
            } else {   
                // 若是一个类的实例, 最后需要调用一下 callParent() 方法
                /**     
                *      var panel = new Ext.Panel({ ... });
                *      Ext.override(panel, {
                *          initComponent: function () {
                *              // extra processing...
                *
                *              this.callParent();
                *          }
                *      });
                */
                var owner = target.self,
                    name, value;

                if (owner && owner.$isClass) {
           
                    for (name in overrides) {
                        if (overrides.hasOwnProperty(name)) {
                            value = overrides[name];

                            if (typeof value == 'function') {
                                //<debug>
                                if (owner.$className) {
                                    value.displayName = owner.$className + '#' + name;
                                }
                                //</debug>

                                value.$name = name;
                                value.$owner = owner;
                                value.$previous = target.hasOwnProperty(name)
                                    ? target[name] // already hooked, so call previous hook
                                    : callOverrideParent; // calls by name on prototype
                            }

                            target[name] = value;
                        }
                    }
                } else {
                    // 若target只是一个普通对象,则调用apply方法即可。
                    Ext.apply(target, overrides);
                }
            }

            return target;
        }
    });                                   

3.3 初始化一些类型验证函数,这里只记录了两个不常见的,剩下的也比较简单

 Ext.apply(Ext, {

       ......

       // 判断是否是 HTMLElement
        isElement: function(value) {
            return value ? value.nodeType === 1 : false;
        },
 
       // 判断是否是TextNode      
        isTextNode: function(value) {
            return value ? value.nodeName === "#text" : false;
        },

       ...... 
    });

3.4

 Ext.apply(Ext, {

         // 复制对象,包括 [], {}, dom, date. 不会产生引用对象。
        clone: function(item) {
            var type,
                i,
                j,
                k,
                clone,
                key;
            
            if (item === null || item === undefined) {
                return item;
            }

            // DOM nodes
            if (item.nodeType && item.cloneNode) {
                return item.cloneNode(true);
            }

            type = toString.call(item);

            // Date
            if (type === '[object Date]') {
                return new Date(item.getTime());
            }


            // Array
            if (type === '[object Array]') {
                i = item.length;

                clone = [];

                while (i--) {
                    clone[i] = Ext.clone(item[i]);
                }
            }
            // Object
            else if (type === '[object Object]' && item.constructor === Object) {
                clone = {};

                for (key in item) {
                    clone[key] = Ext.clone(item[key]);
                }

                if (enumerables) {
                    for (j = enumerables.length; j--;) {
                        k = enumerables[j];
                        if (item.hasOwnProperty(k)) {
                            clone[k] = item[k];
                        }
                    }
                }
            }

            return clone || item;
        },

        ......

});

4. Ext.globalEval

Ext.globalEval = Ext.global.execScript
    ? function(code) {
        // exexScript作用域是全局闭包
        execScript(code);
    }
    : function($$code) {
        (function(){
            // 这里需要让 Ext 指代的是全局变量的Ext对象
            var Ext = this.Ext;
            eval($$code);
        }());
    };

这里还需要多说两句的是 eval & window.eval & window.execScript 的区别

首先 eval 和 window.eval 的区别,可以参考这篇文章。简单点说,就是eval是局部闭包,而window.eval是全局闭包

window.execScript只有IE认识,且也是全局闭包。以后有时间再来详细分析一下三者之间的区别。

-----------------------------一花开五叶 结果自然成-------------------------------------------------
原文地址:https://www.cnblogs.com/zyc-undefined/p/3244796.html