模塊化的理解

模塊化方式

什么是模塊化
所謂的模塊化開發(fā)就是封裝細(xì)節(jié),提供使用接口,彼此之間互不影響,每個(gè)模塊都是實(shí)現(xiàn)某一特定的功能。模塊化開發(fā)的基礎(chǔ)就是函數(shù)

  • 函數(shù)封裝

    • "污染"了全局變量,無法保證不與其他模塊發(fā)生變量名沖突,而且模塊成員之間看不出直接關(guān)系。
  • 對(duì)象方式

    var module1 = {
         _count : 0,
        m1 : function (){
          //...
        },
        m2 : function (){
          //...
        }
    }
    // 這樣的寫法會(huì)暴露所有模塊成員,內(nèi)部狀態(tài)可以被外部改寫。比如,外部代碼可以直接改變內(nèi)部計(jì)數(shù)器的值。module1._count = 1;
    
  • IIFE

    var module1 = (function(){
        var _count = 0;
        var m1 = function(){
          //...
        };
        var m2 = function(){
          //...
        };
        return {
          m1 : m1,
          m2 : m2
        };
      })();
    
  • 放大模式

    • 如果一個(gè)模塊很大,必須分成幾個(gè)部分,或者一個(gè)模塊需要繼承另一個(gè)模塊,這時(shí)就有必要采用"放大模式"(augmentation)。在原有的基礎(chǔ)上擴(kuò)展更多的方法
    var module1 = (function (mod){
        mod.m3 = function () {
          //...
        };
        return mod;
      })(module1);
    
    // 上面的代碼為module1模塊添加了一個(gè)新方法m3(),然后返回新的module1模塊,方便方法連續(xù)調(diào)用。如何防止module1為null或underfined的情況了?
    
  • 寬放大模式

    • 在瀏覽器環(huán)境中,模塊的各個(gè)部分通常都是從網(wǎng)上獲取的,有時(shí)無法知道哪個(gè)部分會(huì)先加載。如果采用上面的寫法,第一個(gè)執(zhí)行的部分有可能加載一個(gè)不存在空對(duì)象,這時(shí)就要采用"寬放大模式"。
    var module1 = (function (mod){
    
            return mod;
      })(window.module1 || {}); // 確保對(duì)象不為空
    
    // 與"放大模式"相比,"寬放大模式"就是"立即執(zhí)行函數(shù)"的參數(shù)可以是空對(duì)象,解決了非空問題。
    
  • 輸入全局變量

    • 獨(dú)立性是模塊的重要特點(diǎn),模塊內(nèi)部最好不與程序的其他部分直接交互。為了在模塊內(nèi)部調(diào)用全局變量,必須顯式地將其他變量輸入模塊。
    var module1 = (function ($, YAHOO) {
        //...
      })(jQuery, YAHOO);
    

COMMONJS 服務(wù)器端同步加載

  1. 再來說說 module.exports 和 exports,用法其實(shí)是相似的,但是不能對(duì) exports直接賦值,不會(huì)有任何效果。
  2. 對(duì)于 CommonJS 和 ES6 中的模塊化的兩者區(qū)別是:
    • 前者支持動(dòng)態(tài)導(dǎo)入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案
    • 前者是同步導(dǎo)入,因?yàn)橛糜诜?wù)端,文件都在本地,同步導(dǎo)入即使卡住主線程影響也不大。而后者是異步導(dǎo)入,因?yàn)橛糜跒g覽器,需要下載文件,如果也采用導(dǎo)入會(huì)對(duì)渲染有很大影響
    • 前者在導(dǎo)出時(shí)都是值拷貝,就算導(dǎo)出的值變了,導(dǎo)入的值也不會(huì)改變,所以如果想更新值,必須重新導(dǎo)入一次。但是后者采用實(shí)時(shí)綁定的方式,導(dǎo)入導(dǎo)出的值都指向同一個(gè)內(nèi)存地址,所以導(dǎo)入值會(huì)跟隨導(dǎo)出值變化
    • 后者會(huì)編譯成 require/exports 來執(zhí)行的

AMD (Asynchronous Module Definition)

"異步模塊定義"。它采用異步方式加載模塊,模塊的加載不影響它后面語句的運(yùn)行。所有依賴這個(gè)模塊的語句,都定義在一個(gè)回調(diào)函數(shù)中,等到加載完成之后,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。

require([module], callback);

requirejs的使用

  1. 為什么要使用requirejs

    • 加載的時(shí)候,瀏覽器會(huì)停止網(wǎng)頁渲染,加載文件越多,網(wǎng)頁失去響應(yīng)的時(shí)間就會(huì)越長(zhǎng);

    • 由于js文件之間存在依賴關(guān)系,因此必須嚴(yán)格保證加載順序(比如上例的1.js要在2.js的前面)

    • 依賴性最大的模塊一定要放到最后加載,當(dāng)依賴關(guān)系很復(fù)雜的時(shí)候,代碼的編寫和維護(hù)都會(huì)變得困難。

    • requirejs 特性

      1. 實(shí)現(xiàn)js文件的異步加載,避免網(wǎng)頁失去響應(yīng);
      2. 管理模塊之間的依賴性,便于代碼的編寫和維護(hù)。
  2. requireJs的加載

    <script src="js/require.js" data-main="js/main"></script>
    
    1. data-main屬性的作用是,指定網(wǎng)頁程序的主模塊。
    2. 在上例中,就是js目錄下面的main.js,這個(gè)文件會(huì)第一個(gè)被require.js加載。
    3. 由于require.js默認(rèn)的文件后綴名是js,所以可以把main.js簡(jiǎn)寫成main。
    
  3. 主模塊的寫法

    主模塊",意思是整個(gè)網(wǎng)頁的入口代碼。它有點(diǎn)像C語言的main()函數(shù),所有代碼都從這兒開始運(yùn)行。下面就來看,怎么寫main.js。

    require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
        // some code here
            // require.js會(huì)先加載jQuery、underscore和backbone,然后再運(yùn)行回調(diào)函數(shù)。主模塊的代碼就寫在回調(diào)函數(shù)中。
      });
    /*
    require()函數(shù)接受兩個(gè)參數(shù)。
        第一個(gè)參數(shù)是一個(gè)數(shù)組,表示所依賴的模塊,上例就是['moduleA', 'moduleB', 'moduleC'],即主模塊依賴這三個(gè)模塊;
        第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),當(dāng)前面指定的模塊都加載成功后,它將被調(diào)用。加載的模塊會(huì)以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊。
    */
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容