引用 extJs 2.0學習筆記(ext.js篇)

研究工具:Dreamweave cs3(裝那個extJs 2.0插件老裝不上)、Aptana(一個好處,好看代碼,有括號匹配,json語法好是好,就是括號多了,搞清在哪兒結束)

  發現,extJs的代碼最喜歡用json語法定義,類基本上都是用json語法定義的。而不是在外面一大路的xx.prototype.yyyy=function(){……}。不過這種語法蠻清晰。我喜歡。

  extJs時面只有一個類:Ext,它是一個靜態類。提供了經常要用到的函數。

Ext.apply = function(o, c, defaults){
    if(defaults){
        // no "this" reference for friendly out of scope calls
        Ext.apply(o, defaults);
    }
    if(o && c && typeof c == 'object'){
        for(var p in c){
            o[p] = c[p];
        }
    }
    return o;
};

  這是apply函數,作用其實相當於克隆,它把對象c中的成員全部複製到o中去。如果有defaults,也把它的內容複製到o中。這兒其實揭示javascript的一種語法:

  javascript中的對象的成員有兩種引用方法:

  一、o.propertyName

  二、o[propertyName]

  這段代碼關鍵就在o[p]=c[p]。這個要理解。儘管如此,但是不能像下面一樣做:

  var newelem=new Object();
  Ext.apply(newelem,Ext.getDom("a1"));
  Ext.getDom("form1").appendChild(newelem);

 

  下面一大段的代碼,由於dw不好看代碼,半天才曉得那兒是個(function(){……Ext.apply(Ext,{……}})(),這是我把概述出來。這樣寫呢,實在有點叫人彆扭,作者的意圖是想把這相關的一段全部放到括號中,以免造成理解上的混亂。能理解。不過,這種寫法不大招人喜歡。

 

        applyIf : function(o, c){
            if(o && c){
                for(var p in c){
                    if(typeof o[p] == "undefined"){ o[p] = c[p]; }
                }
            }
            return o;
        }

  這是applyIf的代碼,事實上,在文檔上面,它的描述有問題,應當是是當o,c兩個對象都存在時,則把o中不存在,c中存在的屬性複製到o中,且屬性名不變。而不是所謂“如果o不存在時就把屬性複製到o中”,哪有這種說法的。另外,判斷一個對象是不是存在,最嚴謹的還是用typeof的方法。

 

addBehaviors : function(o){
            if(!Ext.isReady){
                Ext.onReady(function(){
                    Ext.addBehaviors(o);
                });
                return;
            }
            var cache = {}; 
            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]);
                }
            }
            cache = null;
        }

  這個地方巧妙在於依賴於Ext.isReady。這個屬性我估計應當是在onload第一行將它設成true的,它的作用就是用於標誌當前是不是已經文檔模型加載完了。前面幾行的意思:如果dom模型還沒有加載完,沒有準備好,就將這些事件註冊代碼交給onload去做。即Ext.onReady。

  如果DOM模型已加載完,那麼就馬上註冊事件,區別:前者是延遲註冊、後者是馬上註冊。爲什麼要延遲,因爲DOM都沒有創建完,有些元素在DOM樹中還不存在,當然就沒法設置它了。其餘的地方則不足道,後面的關鍵就是Ext.select了。

 

        id : function(el, prefix){
            prefix = prefix || "ext-gen";
            el = Ext.getDom(el);
            var id = prefix + (++idSeed);
            return el ? (el.id ? el.id : (el.id = id)) : id;
        }

  這兒有一個技巧:prefix = prefix || "ext-gen",這是最簡捷的代碼啊。本來要一個if語句的。

 

  extend、namespace兩個函數硬是沒有看懂,等水平高了再來研究。

 

  urlEncode的源代碼原理簡單,但是,要是我的話還是沒法寫得這麼清楚,主要是情況比較多。這兒主要是學到了數組的push,原來以爲push只能傳一個參數,沒想到能一次傳多個。發現,很多時候,在構造一個複雜的字符串時都是用到數組的。至於urlEncode的作用,就是把一個JSON對象編碼成一個查詢字符串。

        each : function(array, fn, scope){
            if(!Ext.isArray(array)){
                array = [array];
            }
            for(var i = 0, len = array.length; i < len; i++){
                if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
            }
        }

  這個函數的功能並不是像它的名字一樣簡單啊,這兒又學到了:

  一、原來構造單元素數組可以直接這樣寫:a=[a]。

  二、scope在這兒是默認僞調用者,同時,還把當前數組元素值、序號、數組引用都傳過去了。這個可能在fn中用得着。要注意。

  另外就是x===false這個語句要注意。要知道undefined==false。

        callback : function(cb, scope, args, delay){
            if(typeof cb == "function"){
                if(delay){
                    cb.defer(delay, scope, args || []);
                }else{
                    cb.apply(scope, args || []);
                }
            }
        }

  吃了一驚,Function什麼時候有個成員叫defer了?後來才知,defer是extJs擴展出來的。delay是時延。老實說scope這個東西不能言傳只可意會,不看代碼是不清楚的。事實上javascript中的確是存在defer屬性的。用於修飾script元素的,確實是用於延遲script裏面內容的加載。詳情見此處

        destroy : function(){
            for(var i = 0, a = arguments, len = a.length; i < len; i++) {
       var as = a[i];
      if(as){
        if(typeof as.destroy == 'function'){
          as.destroy();
      }
      else if(as.dom){
          as.removeAllListeners();
          as.remove();
      }
                }
            }
        }

  這個函數用來銷燬對象,由代碼可知一點,extJs鼓勵大家在創建自己的類有必要的話就寫destroy。如大量沒用的dom元素。在這裏,destory相當於析構造函數一樣。至於removeAllListenners,remove這兩個函數,它們是Ext.Element類的成員。

  removeNode : isIE ? function(){
            var d;
            return function(n){
                if(n && n.tagName != 'BODY'){
                    d = d || document.createElement('div');
                    d.appendChild(n);
                    d.innerHTML = '';
                }
            }
        }() : function(n){
            if(n && n.parentNode && n.tagName != 'BODY'){
                n.parentNode.removeChild(n);
            }
        }

  這個代碼作用顯然,就是刪除一個結點。但是這個代碼的寫法實在有點讓人難以接受啊。最鬱悶是如果ie,那麼,那個參數n是怎麼傳進去的呢,因爲外面罩住的那個函數沒有參數,本來沒有參數也好辦,關鍵是外面的那個函數根本沒有傳參數給return裏面的函數,這居然也能傳進去,見識到了。

  經過一番實驗與琢磨,發現,其實並不是外面的函數能傳參給裏面的那個函數,實在是因爲那個()用得好,如有:

  var do1=function(){return function(n){}}();

  關鍵是要外面的函數{}之後要馬上“自調用”一下,這樣就會返回一個結果,這個結果是個函數表達式,它就能傳參了。所以如果外面的函數沒有()的話,那麼實際調用將必須寫成:do1()(3)的形式,連寫兩個括號。。這個問題我想了好久,終於想清楚了。

    createCallback : function(/*args...*/){
        // make args available, in function below
        var args = arguments;
        var method = this;
        return function() {
            return method.apply(window, args);
        };
    }

  顧名思意,回調。這個函數是對Function對象的原型擴展。所以,所有函數都有這個成員。例如:

  function A(){}

  B=A.createCallback();

  B();

  最後B()執行調用的是A。有人說,既然調用B就相當於調用A,還不如直接用

  function B(){A.apply(window,this.argments);}

  的確,這樣確實可以達到差不多的目的,但是,寫代碼要注意封裝。儘管這隻有一行代碼,但是,相對於客戶程序員來說,createCallback比apply親切多了,而且,它還節省了不少字符,這就節省帶寬。

  什麼時回調?讓別人來調,那爲什麼不定義在那個調用者裏面?因爲,只有定義在別人的裏面纔可以獲得別人的信息。

  當然,在這兒我還是學到了一點,以前沒意識到,怎樣把外層的this傳給內層的function。只需method=this。

  有一些Ext下的函數並沒有定義在ext.js中。如:Ext.onReady、Ext.reg、Ext.select、Ext.query。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章