初探前端模塊化規範(AMD,CommonJS,UMD,CMD)

      之前,開發中咱們一般使用整套框架(easyui,bootstrap),不得不說,easyui的自定義打包下載,讓我很困惑,由於那個時候,須要手動跟蹤組件依賴,也就是說,你須要本身手動下載相關文件,並注意在頁面的引入順序(好吧,有點耐心,細緻點,總能解決的)。html

     如今,項目規模的增加,業務複雜度的增長,以及客戶對交互與ui的要求不斷提升。咱們基本再也不使用整套框架,都是選擇開源的單一組件,各類組合,來實現相關業務。咱們須要引入大量的插件文件,頁面引入時,如何避免組件的彼此衝突,相互干擾,成爲了很尖銳的問題。(曾經被select.js重寫$坑過的朋友應該有感觸)。前端

爲了解決這個問題,兩種競爭關係的模塊規範AMD和CommonJS問世了,它們容許開發者遵守一種約定的沙箱化和模塊化的方式來寫代碼,這樣就能避免「污染生態系統」。jquery

一 AMD(Asynchronous Module Definition ) 異步模塊加載--主要適用在web客戶端git

以require.js爲主力,在社區推動規範發展。github

下面是隻依賴jquery的模塊foo的代碼:web

    //    文件名: foo.js
    define(['jquery'], function ($) {
        //    方法
        function myFunc(){};
        
        //    暴露公共方法
        return myFunc;
    });

還有稍微複雜點的例子,下面的代碼依賴了多個組件而且暴露多個方法:bootstrap

    //    文件名: foo.js
    define(['jquery', 'underscore'], function ($, _) {
        //    方法
        function a(){};    //    私有方法,由於沒有被返回(見下面)
        function b(){};    //    公共方法,由於被返回了
        function c(){};    //    公共方法,由於被返回了
        //    暴露公共方法
        return {
            b: b,
            c: c
        }
    });

define爲require.js向宿主環境注入的全局方法,用於模塊的定義,它接受的第一個參數是一個依賴數組,標識當前模塊的依賴。它接受的第二個參數是一個回調函數。只有當全部依賴均可用時,回調函數纔會執行。api

注意:數組

一、依賴組件和變量的順序是一一對應的(例如,jquery->$, underscore->_);瀏覽器

二、咱們能夠用任意的變量名來表示依賴組件。假如咱們把$改爲$$,在函數體裏面的全部對jQuery的引用都由$變成了$$;

三、最重要的是你不能在回調函數外面引用變量$和_,由於它相對其它代碼是獨立的。這正是模塊化的目的所在!

四、開發環境中,咱們一般一個模塊一個文件,這樣方便管理,在生產環境中,爲了性能,可使用工具,對文件合併,減小請求。


二 Common JS-通用js模塊化規範--適用於server端。

就像前面的格式同樣,下面是用CommonJS規範實現的foo模塊的寫法:

    //    文件名: foo.js
    //    依賴
    var $ = require('jquery');
    //    方法
    function myFunc(){};

    //    暴露公共方法(一個)
    module.exports = myFunc;

還有更復雜的例子,下面的代碼依賴了多個組件而且暴露多個方法:

    //    文件名: foo.js
    var $ = require('jquery');
    var _ = require('underscore');

    //    methods
    function a(){};    //    私有方法,由於它沒在module.exports中 (見下面)
    function b(){};    //    公共方法,由於它在module.exports中定義了
    function c(){};    //    公共方法,由於它在module.exports中定義了

    //    暴露公共方法
    module.exports = {
        b: b,
        c: c
    };

注意:

一、這裏的require方法用於引入模塊,當前模塊使用module.exports向外界暴露接口。

二、咱們嚴格遵循一個模塊對應一個文件。


雖然看起來已經很不錯了,咱們是否是還能夠更進一步呢?有人但願創建一個與環境無關的通用模塊規範,讓client端和server端的js代碼能夠無縫切換使用。因而產生了兼容性方案UMD

三 UMD(通用模塊規範)

不得不認可,這個模式略難看,可是它兼容了AMD和CommonJS,同時還支持老式的「全局」變量規範:

    (function (root, factory) {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['jquery'], factory);
        } else if (typeof exports === 'object') {
            // Node, CommonJS之類的
            module.exports = factory(require('jquery'));
        } else {
            // 瀏覽器全局變量(root 即 window)
            root.returnExports = factory(root.jQuery);
        }
    }(this, function ($) {
        //    方法
        function myFunc(){};

        //    暴露公共方法
        return myFunc;
    }));

保持跟上面例子同樣的模式,下面是更復雜的例子,它依賴了多個組件而且暴露多個方法:

    (function (root, factory) {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['jquery', 'underscore'], factory);
        } else if (typeof exports === 'object') {
            // Node, CommonJS之類的
            module.exports = factory(require('jquery'), require('underscore'));
        } else {
            // 瀏覽器全局變量(root 即 window)
            root.returnExports = factory(root.jQuery, root._);
        }
    }(this, function ($, _) {
        //    方法
        function a(){};    //    私有方法,由於它沒被返回 (見下面)
        function b(){};    //    公共方法,由於被返回了
        function c(){};    //    公共方法,由於被返回了

        //    暴露公共方法
        return {
            b: b,
            c: c
        }
    }));

四 CMD

CMD是SeaJS 在推廣過程當中對模塊定義的規範化產出

CMD和AMD的區別有如下幾點:

1.對於依賴的模塊AMD是提早執行,CMD是延遲執行。不過RequireJS從2.0開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不經過)。

2.CMD推崇依賴就近,AMD推崇依賴前置。

舉個例子:

//CMD
define( function  (require, exports, module) {
     
     //依賴能夠就近書寫

    var $= require('jquery');

//經過exports向外暴露接口

    exports.do=function(){

            console.log($);

            }

});


總結:

前端發展突飛猛進,每一項技術都有本身的使用場景與侷限,雖然模塊化規範看起來比較簡單,模塊化思惟的創建纔是最讓人惱火的。同時,他們都對應着一系列的技術方案,從開發,測試,構建,打包,到性能優化。前端是一個愈來愈須要專業化的工做。

如何合理的設計,抽象模塊,實施分割,封裝,至於應用到實際生產中,真的是一件須要智慧,體力和勇氣的事情啊

目前本人存在的問題:不能有效的運用於實踐中,思惟一時難以轉變。

歡迎組隊研究,探討。若有錯漏,請指正!

引用/參考:

1  [譯]神馬是AMD, CommonJS, UMD?

JavaSript模塊化

AMD 規範 ,CMD規範 ,AMD 和 CMD 的區別有哪些?

關於 CommonJS AMD CMD UMD

相關文章
相關標籤/搜索