萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> JavaScript中的對象動態加載技術

JavaScript中的對象動態加載技術

 什麼是JavaScript對象動態加載

JavaScript動態加載(JavaScript Object Dynamic Loading) - 之所以叫做動態,是應為其有別與通常的靜態加載形式。

典型的JavaScript靜態加載方式,是通過<script>標簽將我們可能需要的所有JS文件依次嵌入到一個HTML頁面中,當浏覽器執行到<script> 標簽,就會到我們指定的地方去加載JavaScript並運行,這時,文件中定義的無論方法、類、對象等,已經存在與浏覽器,等待被使用。除非HTML頁面被Unload,否則這些東西就一直存在。

而典型的動態加載方式,是不需要任何提前的准備,只有當需要一個JavaScript對象來為我們服務時,我們就臨時去加載它所屬的JS文件,然後使用它,使用完畢,銷毀即可。正所謂“呼之即來,揮之即去”。

就因為這“呼之即來,揮之即去”的能力,使得JavaScript真正的活了起來。

JS動態加載解決了什麼問題

 

  • 給系統減了肥:可以將不必要的JavaScript代碼延遲加載,未用到的功能不加載。
  • 模塊化得以實現:可以將原本大塊的功能或類,分解成合理的小塊,便於管理與維護。
  • 方便的值傳遞:雙向傳值,無拘束。基於JSON,可以傳遞大對象。
  • 可以實現Service:可以基於Service理念,通過核心JavaScript對象使用其他的服務功能對象,完成業務的組裝。

JS動態加載應該有什麼能力

 

  • 可以異步的,或同步的,隨心所遇加載外部JS文件。
  • 加載進來的JS文件的內容可以有效管理,包括作用域,開放性,生命周期。
  • 可以支持面向對象,以對象為基本點而不是方法或變量等。
  • 有好的封裝,可以通過一個句柄操作整個被加載的JS。

傳統JS動態加載的實現

關於JS動態加載的實現,我見過很多種方法。早期的時候,人們想過很多辦法。這些辦法有自己發揮的空間,可以解決一些問題。但是都或多或少的存在弊端,以及實現上的繁瑣,最大的問題就是,它們基本都不是面向對象的。下面就列舉主要的2類:

 

  • 用嵌套iFrame的方式來加載JS文件:這種方式早期最多,通過在頁面中包含一個iFrame,來調用一個另一個包含了<script>標簽的HTML頁面,實現JS的動態加載。最大的弊端就是無法傳遞參數,實現較繁瑣。
  • 臨時創建<script>標簽:這種方式有很多人用。利用JavaScript操作頁面Dom模型,臨時創建一個<script>標簽,然後appendChild到<body>上,或者動態改變已存在<scirpt>標簽的 src屬性。弊端是只能同步加載,必須等待JS文件被讀取完畢,才能進行下一步工作。且傳值是通過調用被加載的JS內的變量實現,雙向傳值困難,作用域弱化。

可以看出以上兩種常見方式,都無法滿足我們的要求。

更優秀的解決方案

得益於神奇如阿拉丁神燈般的 eval() ,我們就可以實現以上所有的願望 :) 。

繞了那麼大圈子,想了那麼多辦法。其實最簡單的方法就在眼皮底下.

第一部分-調用方 main.js文件:

//動態讀取JS對象的方法

//@FileName:要讀取的JS對象URL,可以是本地路徑。

//@TheParameters:需要傳遞給被加載對象的參數,可以是任何對象。

function loadJSObj(FileName,TheParameters){ 
    Ext.Ajax.request({   //異步調用方法 
        url: FileName,   //調用URL 
        scope: this,   
        success: function(response){   //成功後的回調方法response為返回內容
            var remoteObj = eval(response.responseText); 
            var mod = null; 
            mod = new remoteObj(TheParameters);

            return mod; 
        }, 
        failure:function(){   //失敗後的回調方法 
            alert(name+' - 讀取失敗,請檢查網絡或文件。');

            return null; 
        } 
    }); 
}

這段代碼使用Extjs類庫封裝的異步讀取方法Ext.Ajax.request()。只是為了方便。如果你使用未封裝的XMLHttpRequest對象也沒什麼問題。

先大概說下loadJSObj方法干的事情是:

 

  • 用XMLHttpRequest來了一次Ajax請求,將想要加載的JS文件源代碼讀過來。
  • 利用eval函數將剛才讀到的遠程JavaScript類實例化成為本地的對象(期間傳遞了構造參數)。
  • 返回這個對象,供使用。

此處關鍵的代碼在於

            var remoteObj = eval(response.responseText); 
            var mod = null; 
            mod = new remoteObj(TheParameters);

            return mod;

可以看到,我們直接將被讀取的JS文件傳進eval 函數執行。並返回一個叫做 remoteObj的東西,這個東西其實就是被讀取的JS的句柄(一個類,定義在被讀取JS中的類,後面會詳細說到),通過將remoteObj實例化,即mod = new remoteObj(參數) 就可以通過 mod 對象對被讀取的JS隨心所欲了操作了。

如此一來,遠程的JS就被我們按照參數中指定的要求實例化成本地對象了,可以使用了。但是…這只是一相情願。因為被讀取的JS得符合我們的要求,才能“兩廂情願”,最終得到結果…

第二部分 - 被調用方 login.js文件:

要想符合要求,被讀取的JS文件也必須按照一定的規則來寫。

//用戶登錄類

Ext.extend(eueuy.module,{ 
    init:function(){    
        //==Variables==// 
        var userName = this.parameters.un;  //獲取傳遞進來的參數un 
        var passWord = this.parameters.pwd;   //獲取傳遞進來的參數pwd 
       
        //==Methods==// 
        //登錄方法 
        function loginOn(){ 
            if (userName=='eueuy' || passWord=='123'){ 
                return true;                
            }else{ 
                return false; 
            } 
        } 
        //登出方法        
        function loginOff(){ 
            alert('歡迎再來');

        } 
    } 
});

我們先看看這個登錄類干了什麼:

 

  • 繼承自eueuy.moudle,並重寫了構造函數。
  • 接收了2個傳遞進來的初始化參數,un 和 pwd。
  • 定義了2個成員方法和一個成員變量。

沒有任何特別的東西,就是Ext.extend方法用的有點怪,區別於平常的 XXX = Ext.extend();

沒有賦值符號和類名。這恰恰是一個關鍵點:

類的名字必須留空

為什麼這樣寫?因為這樣一來,這個沒有類名的類, 就可以在eval()函數執行他的時候,再給他定義類名,這樣就將類名的定義留在了調用的時候

copyright © 萬盛學電腦網 all rights reserved