ExtJs 源碼筆記------Ext.js

ExtJs 源碼筆記------Ext.js

最近準備系統的學習一下Ext的源碼,SO,話很少說,從第一篇開始。html

首先,先看一下Ext.js這個文件的代碼結構:node

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

(function(){
     
     // 定義一些局部變量
     var ......

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

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

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

代碼的結構不難,可是仔細看下來,有些細節的地方仍是很值得回味一番。下面具體分析一下我對源碼的理解,水平有限,不足之處還望各位看官指正。閉包

1. 定義局部變量app

  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.applydom

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中拷貝對象的內容,能夠狠狠的點擊這裏ide

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.2this

 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 初始化一些類型驗證函數,這裏只記錄了兩個不常見的,剩下的也比較簡單spa

 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認識,且也是全局閉包。之後有時間再來詳細分析一下三者之間的區別。

相關文章
相關標籤/搜索