seajs是淘寶的前UED玉伯寫的,可以在http://seajs.org/docs/看到更全面的說明
在 Sea.js 中,所有 JavaScript 模塊都遵循 CMD(Common Module Definition) 模塊定義規範。該規範明確了模塊的基本書寫格式和基本交互規則。
在 CMD 規範中,一個模塊就是一個文件。代碼的書寫格式如下:define(factory);
define是一個全局函數,用來定義模塊
接收factory參數,factory可以是一個函數,也可以是一個對象或者字符串。
factory爲對象或者字符串時表示該模塊的接口就是該對象或者字符串,
eg:
define({"foo":"bar"})(對象接口)
define("I'm a templete.My name is {{name}}.")(字符串接口)
define(function(require,exports,module){//模塊代碼
})
define也可以接受兩個以上的參數:define(id,deps,factory)(id 表示模塊標識,數組deps表示模塊依賴,他們可以省略,省略的時候可以通過構建工具自動生成。帶 id 和 deps 參數的 define 用法不屬於 CMD 規範,而屬於 Modules/Transport 規範。)
define.cmd:一個空對象,可用來判斷當前頁面是否有cmd模塊加載器:
if (typeof define === "function" && define.cmd) {
// 有 Sea.js 等 CMD 模塊加載器存在}
}
require是factory函數的第一個參數,它是一個函數,接受模塊標識作爲其唯一參數,用來獲取其他模塊提供的接口,require不能被修改,只有這一種唯一的寫法,require的參數必須是字符串直接量:define(function(require,exports){
var a=require("./a");//獲取模塊a的接口
a.doSomething();//調用模塊a的方法
})
有時需要加載動態依賴,這時可以加一個判斷,如
if (todayIsWeekend)
require("play");
else
require("work");
但是從靜態文件的角度來看,這個模塊同時依賴play和work這兩個模塊,可以使用require.async來進行條件加載。
require.async用於在模塊內部異步加載模塊,並在加載完成後執行指定回調函數,回調函數可以缺省:
define(function(require,exports){
//異步加載一個模塊
require.async("./b",function(b){
b.doSomething();
});
require.async(["./c","./d"],function(c,d){
//異步加載多個模塊
c.doSomething();
d.doSomething();
});
})
小結:require是同步執行的,require.async 則是異步回調執行。require.async 一般用來加載可延遲異步加載的模塊。
require.resolve(id):
使用模塊系統內部的路徑解析機制來解析並返回模塊路徑。該函數不會加載模塊,只會返回解析後的絕對路徑。這可以用來獲取模塊路徑,一般用在插件環境可能需要動態拼接模塊路徑的情況下。
exports是一個對象,用來提供模塊對外的接口:
define(function(require,exports){
exports.foo="foo";//對外提供foo屬性
exports.doSomething=function(){}//對外提供doSomething方法
})
除了給exports對象增加成員,還可以通過return直接向外提供模塊接口:
define(function(require){
return {
"foo":"foo",
doSomething:function(){}
}
})
如果return語句是代碼中的唯一代碼,也可以直接寫成:
define({
"foo":"foo",
doSomething:function(){}
})
上面這種格式很適合定義jsonp模塊。
下面這種寫法不正確:
define(function(require, exports) {
// 錯誤用法!!!
exports = {
foo: 'bar',
doSomething: function() {};
};
});
正確的寫法應該是:
define(function(require, exports,module) {
module.exports = {
foo: 'bar',
doSomething: function() {};
};
});
exports僅僅是module.exports的一個引用,在factory內部給exports賦值,並不能改變module.exports的值,不能用來更改模塊接口。
module是一個對象,用來存儲與當前模塊相關聯的一些屬性和方法:
module.id:模塊的唯一標識
module.uri:根據模塊系統的路徑解析規則得到的模塊絕對路徑(一般情況下,沒有在define中手寫id參數的時候,module.id===module.uri)
module.dependencies是一個數組,表示當前模塊的依賴
module.exports:當前模塊對外的接口
傳給factory構造函數的參數exports是module.exports對象的一個引用。只通過exports來提供接口,有時無法滿足開發需求。比如當接口是某個類的實例時,需要通過module.exports來實現:
define(function(require, exports, module) {
// exports 是 module.exports 的一個引用
console.log(module.exports === exports); // true
// 重新給 module.exports 賦值
module.exports = new SomeClass();
// exports 不再等於 module.exports
console.log(module.exports === exports); // false
});
對module.exports的賦值需要同步執行,不能放在回調函數裏面