轉(zhuǎn)載于作者:linwalker
via:http://www.reibang.com/p/d67bc79976e6
前端模塊規(guī)范有三種:CommonJs,AMD和CMD。
CommonJs用在服務(wù)器端,AMD和CMD用在瀏覽器環(huán)境栽渴。
AMD 是 RequireJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出茉继。
CMD 是 SeaJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出坯临。
AMD:提前執(zhí)行(異步加載:依賴先執(zhí)行)+延遲執(zhí)行
CMD:延遲執(zhí)行(運行到需加載纳本,根據(jù)順序執(zhí)行)
模塊
函數(shù)寫法
function f1(){ //...}function f2(){ //...}
模塊就是實現(xiàn)特定功能的文件苔可,把幾個函數(shù)放在一個文件里就構(gòu)成了一個模塊既绕。需要的時候加載這個文件啄刹,調(diào)用其中的函數(shù)即可。
但這樣做會污染全局變量凄贩,無法保證不與其他模塊發(fā)生變量名沖突誓军,而且模塊成員之間沒什么關(guān)系。
對象寫法
var module = { star : 0, f1 : function (){ //... }, f2 : function (){ //... }};module.f1();module.star = 1;
模塊寫成一個對象疲扎,模塊成員都封裝在對象里昵时,通過調(diào)用對象屬性,訪問使用模塊成員椒丧。但同時也暴露了模塊成員壹甥,外部可以修改模塊內(nèi)部狀態(tài)。
立即執(zhí)行函數(shù)
var module = (function(){ var star = 0; var f1 = function (){ console.log('ok'); }; var f2 = function (){ //... }; return { f1:f1, f2:f2 }; })();module.f1(); //okconsole.log(module.star) //undefined
外部無法訪問內(nèi)部私有變量
CommonJs
CommonJS是服務(wù)器端模塊的規(guī)范壶熏,由Node推廣使用句柠。由于服務(wù)端編程的復(fù)雜性,如果沒有模塊很難與操作系統(tǒng)及其他應(yīng)用程序互動。使用方法如下:
math.jsexports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum;};increment.jsvar add = require('math').add;exports.increment = function(val) { return add(val, 1);};index.jsvar increment = require('increment').increment;var a = increment(1); //2
根據(jù)CommonJS規(guī)范:
一個單獨的文件就是一個模塊溯职。每一個模塊都是一個單獨的作用域精盅,也就是說,在該模塊內(nèi)部定義的變量谜酒,無法被其他模塊讀取叹俏,除非定義為global對象的屬性。
輸出模塊變量的最好方法是使用module.exports對象僻族。
加載模塊使用require方法粘驰,該方法讀取一個文件并執(zhí)行,返回文件內(nèi)部的module.exports對象
仔細(xì)看上面的代碼述么,您會注意到 require 是同步的蝌数。模塊系統(tǒng)需要同步讀取模塊文件內(nèi)容,并編譯執(zhí)行以得到模塊接口碉输。
然而籽前, 這在瀏覽器端問題多多。
瀏覽器端敷钾,加載 Java 最佳枝哄、最容易的方式是在 document 中插入<>標(biāo)簽。但腳本標(biāo)簽天生異步阻荒,傳統(tǒng) CommonJS 模塊在瀏覽器環(huán)境中無法正常加載挠锥。
解決思路之一是,開發(fā)一個服務(wù)器端組件侨赡,對模塊代碼作靜態(tài)分析蓖租,將模塊與它的依賴列表一起返回給瀏覽器端。 這很好使羊壹,但需要服務(wù)器安裝額外的組件蓖宦,并因此要調(diào)整一系列底層架構(gòu)。
另一種解決思路是油猫,用一套標(biāo)準(zhǔn)模板來封裝模塊定義:
define(function(require, exports, module) { // The module code goes here});
這套模板代碼為模塊加載器提供了機(jī)會稠茂,使其能在模塊代碼執(zhí)行之前,對模塊代碼進(jìn)行靜態(tài)分析情妖,并動態(tài)生成依賴列表睬关。
math.jsdefine(function(require, exports, module) { exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; };});increment.jsdefine(function(require, exports, module) { var add = require('math').add; exports.increment = function(val) { return add(val, 1); };});index.jsdefine(function(require, exports, module) { var inc = require('increment').increment; inc(1); // 2});AMD
AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"毡证。由于不是Java原生支持电爹,使用AMD規(guī)范進(jìn)行頁面開發(fā)需要用到對應(yīng)的庫函數(shù),也就是大名鼎鼎RequireJS料睛,實際上AMD 是 RequireJS 在推廣過程中對模塊定義的規(guī)范化的產(chǎn)出
它采用異步方式加載模塊丐箩,模塊的加載不影響它后面語句的運行摇邦。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中雏蛮,等到加載完成之后涎嚼,這個回調(diào)函數(shù)才會運行阱州。
RequireJS主要解決兩個問題
多個js文件可能有依賴關(guān)系挑秉,被依賴的文件需要早于依賴它的文件加載到瀏覽器
js加載的時候瀏覽器會停止頁面渲染,加載文件越多苔货,頁面失去響應(yīng)時間越長
RequireJs也采用require()語句加載模塊犀概,但是不同于CommonJS,它要求兩個參數(shù):
第一個參數(shù)[module]夜惭,是一個數(shù)組姻灶,里面的成員就是要加載的模塊;第二個參數(shù)callback诈茧,則是加載成功之后的回調(diào)函數(shù)产喉。math.add()與math模塊加載不是同步的,瀏覽器不會發(fā)生假死敢会。
require([module], callback);require([increment'], function (increment) { increment.add(1);});
define()函數(shù)
RequireJS定義了一個函數(shù) define曾沈,它是全局變量,用來定義模塊:
define(id?, dependencies?, factory);
參數(shù)說明:
id:指定義中模塊的名字鸥昏,可選塞俱;如果沒有提供該參數(shù),模塊的名字應(yīng)該默認(rèn)為模塊加載器請求的指定腳本的名字吏垮。如果提供了該參數(shù)障涯,模塊名必須是“頂級”的和絕對的(不允許相對名字)。
依賴dependencies:是一個當(dāng)前模塊依賴的膳汪,已被模塊定義的模塊標(biāo)識的數(shù)組字面量唯蝶。
依賴參數(shù)是可選的,如果忽略此參數(shù)遗嗽,它應(yīng)該默認(rèn)為["require", "exports", "module"]粘我。然而,如果工廠方法的長度屬性小于3媳谁,加載器會選擇以函數(shù)的長度屬性指定的參數(shù)個數(shù)調(diào)用工廠方法涂滴。
工廠方法factory,模塊初始化要執(zhí)行的函數(shù)或?qū)ο笄缫簟H绻麨楹瘮?shù)柔纵,它應(yīng)該只被執(zhí)行一次。如果是對象锤躁,此對象應(yīng)該為模塊的輸出值搁料。
來舉個例子看看:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: return require("beta").verb(); } });
RequireJs使用例子
require.config是用來定義別名的,在paths屬性下配置別名。然后通過requirejs(參數(shù)一郭计,參數(shù)二)霸琴;參數(shù)一是數(shù)組,傳入我們需要引用的模塊名昭伸,第二個參數(shù)是個回調(diào)函數(shù)梧乘,回調(diào)函數(shù)傳入一個變量,代替剛才所引入的模塊庐杨。
main.js//別名配置requirejs.config({ paths: { jquery: 'jquery.min' //可以省略.js }});//引入模塊选调,用變量$表示jquery模塊requirejs(['jquery'], function ($) { $('body').css('background-color','red');});
引入模塊也可以只寫require()。requirejs通過define()定義模塊灵份,定義的參數(shù)上同仁堪。在此模塊內(nèi)的方法和變量外部是無法訪問的,只有通過return返回才行.
math.jsdefine('math',['jquery'], function ($) {//引入jQuery模塊 return { add: function(x,y){ return x + y; } };});
將該模塊命名為math.js保存填渠。
require(['jquery','math'], function ($,math) { console.log(math.add(10,100));//110});
main.js引入模塊方法
CMD
CMD 即Common Module Definition通用模塊定義弦聂,CMD規(guī)范是國內(nèi)發(fā)展出來的,就像AMD有個requireJS氛什,CMD有個瀏覽器的實現(xiàn)SeaJS莺葫,SeaJS要解決的問題和requireJS一樣,只不過在模塊定義方式和模塊加載(可以說運行屉更、解析)時機(jī)上有所不同徙融。
在 CMD 規(guī)范中,一個模塊就是一個文件瑰谜。代碼的書寫格式如下:
define(function(require, exports, module) { // 模塊代碼});
require是可以把其他模塊導(dǎo)入進(jìn)來的一個參數(shù);而exports是可以把模塊內(nèi)的一些屬性和方法導(dǎo)出的;module 是一個對象欺冀,上面存儲了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法。
AMD是依賴關(guān)系前置,在定義模塊的時候就要聲明其依賴的模塊;
CMD是按需加載依賴就近,只有在用到某個模塊的時候再去require:
// CMDdefine(function(require, exports, module) { var a = require('./a') a.doSomething() // 此處略去 100 行 var b = require('./b') // 依賴可以就近書寫 b.doSomething() // ... })// AMD 默認(rèn)推薦的是define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好 a.doSomething() // 此處略去 100 行 b.doSomething() ...})
seajs使用例子
// 定義模塊 myModule.jsdefine(function(require, exports, module) { var $ = require('jquery.js') $('div').addClass('active'); exports.data = 1;});// 加載模塊seajs.use(['myModule.js'], function(my){ var star= my.data; console.log(star); //1});