之前,開發中咱們一般使用整套框架(easyui,bootstrap),不得不說,easyui的自定義打包下載,讓我很困惑,由於那個時候,須要手動跟蹤組件依賴,也就是說,你須要本身手動下載相關文件,並注意在頁面的引入順序(好吧,有點耐心,細緻點,總能解決的)。html
如今,項目規模的增加,業務複雜度的增長,以及客戶對交互與ui的要求不斷提升。咱們基本再也不使用整套框架,都是選擇開源的單一組件,各類組合,來實現相關業務。咱們須要引入大量的插件文件,頁面引入時,如何避免組件的彼此衝突,相互干擾,成爲了很尖銳的問題。(曾經被select.js重寫$坑過的朋友應該有感觸)。前端
爲了解決這個問題,兩種競爭關係的模塊規範AMD和CommonJS問世了,它們容許開發者遵守一種約定的沙箱化和模塊化的方式來寫代碼,這樣就能避免「污染生態系統」。jquery
一 AMD(Asynchronous Module Definition ) 異步模塊加載--主要適用在web客戶端git
以require.js爲主力,在社區推動規範發展。github
// 文件名: foo.js define(['jquery'], function ($) { // 方法 function myFunc(){}; // 暴露公共方法 return myFunc; });
// 文件名: 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端。
// 文件名: 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(通用模塊規範)
(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($);
}
});
總結:
前端發展突飛猛進,每一項技術都有本身的使用場景與侷限,雖然模塊化規範看起來比較簡單,模塊化思惟的創建纔是最讓人惱火的。同時,他們都對應着一系列的技術方案,從開發,測試,構建,打包,到性能優化。前端是一個愈來愈須要專業化的工做。
如何合理的設計,抽象模塊,實施分割,封裝,至於應用到實際生產中,真的是一件須要智慧,體力和勇氣的事情啊。
目前本人存在的問題:不能有效的運用於實踐中,思惟一時難以轉變。
歡迎組隊研究,探討。若有錯漏,請指正!
引用/參考: