CMD 模塊定義規(guī)范
在?Sea.js?中狭归,所有?JavaScript?模塊都遵循?CMD(Common?Module?Definition)?模塊定義規(guī)范。該規(guī)范明確了模塊的基本書寫格式和基本交互規(guī)則如贷。
在?CMD?規(guī)范中,一個(gè)模塊就是一個(gè)文件。代碼的書寫格式如下:
define(factory);
defineFunction
define是一個(gè)全局函數(shù)谣拣,用來定義模塊募寨。
definedefine(factory)
define接受factory參數(shù),factory可以是一個(gè)函數(shù)森缠,也可以是一個(gè)對(duì)象或字符串拔鹰。
factory為對(duì)象、字符串時(shí)贵涵,表示模塊的接口就是該對(duì)象列肢、字符串。比如可以如下定義一個(gè)?JSON?數(shù)據(jù)模塊:
define({"foo":"bar"});
也可以通過字符串定義模板模塊:
define('I?am?a?template.?My?name?is?{{name}}.');
factory為函數(shù)時(shí)宾茂,表示是模塊的構(gòu)造方法瓷马。執(zhí)行該構(gòu)造方法,可以得到模塊向外提供的接口跨晴。factory方法在執(zhí)行時(shí)欧聘,默認(rèn)會(huì)傳入三個(gè)參數(shù):require、exports和module:
define(function(require,exports,module)?{
//?模塊代碼
});
definedefine(id?,?deps?,?factory)
define也可以接受兩個(gè)以上參數(shù)坟奥。字符串id表示模塊標(biāo)識(shí)树瞭,數(shù)組deps是模塊依賴。比如:
define('hello',?['jquery'],function(require,exports,module)?{
//?模塊代碼
});
id和deps參數(shù)可以省略爱谁。省略時(shí)晒喷,可以通過構(gòu)建工具自動(dòng)生成。
注意:帶id和deps參數(shù)的define用法不屬于?CMD?規(guī)范访敌,而屬于Modules/Transport規(guī)范凉敲。
define.cmdObject
一個(gè)空對(duì)象,可用來判定當(dāng)前頁面是否有?CMD?模塊加載器:
if(typeofdefine==="function"&&define.cmd)?{
//?有?Sea.js?等?CMD?模塊加載器存在
}
requireFunction
require是factory函數(shù)的第一個(gè)參數(shù)寺旺。
requirerequire(id)
require是一個(gè)方法爷抓,接受模塊標(biāo)識(shí)作為唯一參數(shù),用來獲取其他模塊提供的接口阻塑。
define(function(require,exports)?{
//?獲取模塊?a?的接口
vara=require('./a');
//?調(diào)用模塊?a?的方法
a.doSomething();
});
注意:在開發(fā)時(shí)蓝撇,require的書寫需要遵循一些簡(jiǎn)單約定。
require.asyncrequire.async(id,?callback?)
require.async方法用來在模塊內(nèi)部異步加載模塊陈莽,并在加載完成后執(zhí)行指定回調(diào)渤昌。callback參數(shù)可選。
define(function(require,exports,module)?{
//?異步加載一個(gè)模塊走搁,在加載完成時(shí)独柑,執(zhí)行回調(diào)
require.async('./b',function(b)?{
b.doSomething();
});
//?異步加載多個(gè)模塊,在加載完成時(shí)私植,執(zhí)行回調(diào)
require.async(['./c','./d'],function(c,?d)?{
c.doSomething();
d.doSomething();
});
});
注意:require是同步往下執(zhí)行忌栅,require.async則是異步回調(diào)執(zhí)行。require.async一般用來加載可延遲異步加載的模塊曲稼。
require.resolverequire.resolve(id)
使用模塊系統(tǒng)內(nèi)部的路徑解析機(jī)制來解析并返回模塊路徑索绪。該函數(shù)不會(huì)加載模塊湖员,只返回解析后的絕對(duì)路徑。
define(function(require,exports)?{
console.log(require.resolve('./b'));
//?==>?http://example.com/path/to/b.js
});
這可以用來獲取模塊路徑者春,一般用在插件環(huán)境或需動(dòng)態(tài)拼接模塊路徑的場(chǎng)景下破衔。
exportsObject
exports是一個(gè)對(duì)象,用來向外提供模塊接口钱烟。
define(function(require,exports)?{
//?對(duì)外提供?foo?屬性
exports.foo='bar';
//?對(duì)外提供?doSomething?方法
exports.doSomething=function()?{};
});
除了給exports對(duì)象增加成員晰筛,還可以使用return直接向外提供接口。
define(function(require)?{
//?通過?return?直接提供接口
return{
foo:'bar',
doSomething:function()?{}
};
});
如果return語句是模塊中的唯一代碼拴袭,還可簡(jiǎn)化為:
define({
foo:'bar',
doSomething:function()?{}
});
上面這種格式特別適合定義?JSONP?模塊读第。
特別注意:下面這種寫法是錯(cuò)誤的!
define(function(require,exports)?{
//?錯(cuò)誤用法S悼獭怜瞒!!
exports={
foo:'bar',
doSomething:function()?{}
};
});
正確的寫法是用return或者給module.exports賦值:
define(function(require,exports,module)?{
//?正確寫法
module.exports={
foo:'bar',
doSomething:function()?{}
};
});
提示:exports僅僅是module.exports的一個(gè)引用。在factory內(nèi)部給exports重新賦值時(shí)般哼,并不會(huì)改變module.exports的值吴汪。因此給exports賦值是無效的,不能用來更改模塊接口蒸眠。
moduleObject
module是一個(gè)對(duì)象漾橙,上面存儲(chǔ)了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法。
module.idString
模塊的唯一標(biāo)識(shí)楞卡。
define('id',?[],function(require,exports,module)?{
//?模塊代碼
});
上面代碼中霜运,define的第一個(gè)參數(shù)就是模塊標(biāo)識(shí)。
module.uriString
根據(jù)模塊系統(tǒng)的路徑解析規(guī)則得到的模塊絕對(duì)路徑蒋腮。
define(function(require,exports,module)?{
console.log(module.uri);
//?==>?http://example.com/path/to/this/file.js
});
一般情況下(沒有在define中手寫id參數(shù)時(shí))淘捡,module.id的值就是module.uri,兩者完全相同池摧。
module.dependenciesArray
dependencies是一個(gè)數(shù)組焦除,表示當(dāng)前模塊的依賴。
module.exportsObject
當(dāng)前模塊對(duì)外提供的接口作彤。
傳給factory構(gòu)造方法的exports參數(shù)是module.exports對(duì)象的一個(gè)引用膘魄。只通過exports參數(shù)來提供接口,有時(shí)無法滿足開發(fā)者的所有需求宦棺。?比如當(dāng)模塊的接口是某個(gè)類的實(shí)例時(shí),需要通過module.exports來實(shí)現(xiàn):
define(function(require,exports,module)?{
//?exports?是?module.exports?的一個(gè)引用
console.log(module.exports===exports);//?true
//?重新給?module.exports?賦值
module.exports=newSomeClass();
//?exports?不再等于?module.exports
console.log(module.exports===exports);//?false
});
注意:對(duì)module.exports的賦值需要同步執(zhí)行黔帕,不能放在回調(diào)函數(shù)里代咸。下面這樣是不行的:
//?x.jsdefine(function(require,exports,module)?{
//?錯(cuò)誤用法
setTimeout(function()?{
module.exports={?a:"hello"};
},0);
});
在?y.js?里有調(diào)用到上面的?x.js:
//?y.jsdefine(function(require,exports,module)?{
varx=require('./x');
//?無法立刻得到模塊?x?的屬性?a
console.log(x.a);//?undefined
});