讀Ext之一(實用方法)


第一句

window.undefined = window.undefined;  

  

兼容IE6以下的瀏覽器,有人 解釋過了。

 

定義Ext全局變量

Ext = {
    version : '3.1.0'
};

注意這里沒有使用var,不使用var聲明變量被認為是不好的編程習慣,尤其是函數內聲明變量不寫var更被稱為是無窮無盡的Bug根源。這里則不會,因為變量Ext是該庫唯一的全局變量(命名空間)。其它Ext源碼中的變量聲明都加上了var。

 

給Ext添加靜態apply方法,該方法是核心方法之一,會用其擴展Ext。

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;
};

該方法有兩種執行方式:

其一,只傳o,c時直接將c上的所有屬性/方法拷貝給o后返回;

其二,defaults也傳時,會將defaults,c上的所有屬性/方法都拷貝給o。這里實現的很巧妙,同時有點繞人。

三個參數都傳,會執行Ext.apply(o, defaults),即自身實現中調用自身。defaults為c,即當傳兩個參數時會直接進行對象拷貝。舉個例子一目了然,在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){
        	alert(p); // 此處是添加的輸出語句
            o[p] = c[p];
        }
    }
    return o;
};
var obj = {}, obj1 = {name:'jack'}, obj2 = {age:33};
Ext.apply(obj,obj1,obj2);

會發現先彈出age,再是name。即先拷貝defaults,再是c。

 

接下來是個自執行的匿名函數,執行完后給Ext上擴充許多實用屬性或方法。先定義了一些局部變量idSeed,瀏覽器判斷之類。idSeed在做Dom緩存時用到。接下來,

if(isIE6){
    try{
        DOC.execCommand("BackgroundImageCache", false, true);
    }catch(e){}
}

這段代碼用來解決IE6下css背景圖不緩存bug,也 有人 解釋過了。

 

接下就是一個Ext.apply(Ext,{...}),給Ext對象擴展許多實用屬性及方法。

 

注意 Ext.isStrict 並非判斷html文檔模式為嚴格模式,而是指標准模式,如<!DOCTYPE HTML>聲明會返回true。關於文檔模式猛擊:http://hsivonen.iki.fi/doctype ,國內的 秦歌 翻譯了該篇文章。

 

Ext.isSecure 判斷采用https或是其它。

 

Ext.applyIf 設計的很巧妙,它會把對象沒有的屬性和方法拷貝下來,已經有的則不拷貝。Ext.apply 則會覆蓋已有的屬性/方法。

ECMAScript 5已經發布1年多了,添加了一些新的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的擴展很優雅。
 

Ext.id方法會為HTMLElement元素隨機生成一個id,默認以"ext-gen"開頭。

 

接下來是Ext.extend方法,該方法也是核心方法之一,整個ext框架繼承都是以該方法來擴展的。該方法實現依賴於Ext.override,先看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的原型上。需要注意的是后面的if判斷,IE中for in不能遍歷對象的Object的toSting等方法,因此需要特別處理一下。我測試IE9 beta重寫對象的內置方法如toString后是可用for in遍歷的,見 for in的缺陷  。IE9 beta剛剛發布,不知今后Ext團隊是否會修改此處的判斷。

 

Ext.extend是js繼承最經典的實現方式了,我曾經模仿其(簡化版)應用在 51ditu 。

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(Ext.isObject(sp)){
            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.superclass = sbp.supr = (function(){
            return spp;
        });
        sbp.override = io;
        Ext.override(sb, overrides);
        sb.extend = function(o){return Ext.extend(sb, o);};
        return sb;
    };
}(),

整體瀏覽,可以看到 Ext.extend 的實現是通過一個匿名函數執行,執行后返回function,這個function才是真正的Ext.extend。

匿名函數中有兩個私有函數io,oc。這種組織代碼的方式非常簡練,通過匿名函數自執行,在匿名函數中你可以做任何復雜的操作,最終的目的返回需要的接口函數或類。

 

有三個參數,sb、sp、overrides分別代表subClass(子類)、superClass(父類)及覆蓋子類的配置參數。

 

以下分三種情況討論,第一,二種情況Ext.extend的第二個參數都是對象類型

 

1, Ext.extend不光是用來實現類繼承的,還可以用來寫類,一年前 討論 過 。 

2, 用來擴展Ext庫自身類,這種情況是比較頻繁的

MyGridPanel = Ext.extend(Ext.grid.GridPanel, {
    constructor: function(config) {
        MyGridPanel.superclass.constructor.apply(this, arguments);
    },
    yourMethod: function() {
        // etc.
    }
});

這里以Ext.grid.GridPanel為基礎,生成了一個新類MyGridPanel

 

3, 真正意義類繼承,即第一,二個參數都是類(function)。1年前也總結過js如何實現 繼承 及 工具函數 。

 

篇幅已經很長了,重點說下 Ext.apply, Ext.applyif, Ext.override, Ext.extend 的區別 :

 

Ext.apply, Ext.applyif, Ext.override 都是對對象 進行擴展的方法,Ext.extend則是對 操作的方法。

 

Ext.apply 擴展時對已經存在的屬性/方法會被覆蓋掉, 通常用它來擴展普通對象.

Ext.applyif 擴展時不會覆蓋已經存在的屬性/方法,通常用它來擴展核心js,如Array.prototype,String.prototype等。

Ext.override 擴展某一個類的原型,可以覆蓋toString方法。

 

Ext.extend 用來寫類或繼承,或者說用來擴展類。

 

 

Ext-2012-4-21.rar

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM