上一篇咱們介紹了AMD規範,異步模塊的定義與加載,咱們完成了定義的部分。接下來,咱們來完成加載的部分。javascript
咱們以前已經能夠用define來定義模塊了,那麼如今怎麼去使用的?咱們只是把定義好的模塊存進了倉庫,用的時候還須要一個方法來使用它。html
讓咱們先來用define來定義一些模塊:java
define("a" , [] , function(){ //無依賴模塊 return 1; }); define("b" , ["a"] , function(a){ //有一個依賴的模塊 return ++a; }); define("c" , ["a","b"] , function(a,b){ //有兩個依賴的模塊 一會咱們要使用這個模塊 return a+b; });
這裏定義了3個模塊,其中有一個沒有依賴,兩個是存在依賴模塊的模塊。緩存
而後咱們須要一個方法來使用定義好的模塊:(對於apply和call方法不懂的話,能夠移步個人另外一篇文章:來聊聊apply和call)app
var noop = function(){}; //爲apply方法準備的一個空函數; function use(name){ //參數:模塊名 if(modules[name]){ // 若是模塊定義過: var module = modules[name]; //建立一個副本 if(!module.entity){ //若是實例不存在,說明是第一次建立 var args = []; for(var i=0;i<module.dependencies.length;i++){ //遍歷依賴列表 modules[module.dependencies[i]].entity ? //依賴模塊的實例以存在的話 args.push(modules[module.dependencies[i]].entity) : //直接獲取實例(緩存方法), args.push(this.use(module.dependencies[i])); //否則單獨獲取一次 }; module.entity = module.fn.apply(noop , args); //用apply方法爲模塊實例擴展 }; return module.entity; //之後調用能夠直接調用緩存 }else{ throw new Error("Error:"+ name +" is not define"); // 若是沒有定義模塊,直接拋出一個錯誤. } };
這裏咱們定義了一個使用模塊的方法,經過模塊名來調用定義過的模塊。而使用過一次的模塊,咱們把它存入緩存中,這樣之後再次使用時,直接調用它的實例就能夠了。框架
那麼接下來咱們來用這個方法來使用咱們定義好的模塊:異步
var d = use("c"); console.log(d)//輸出3
這樣咱們就能使用任意咱們定義過的模塊了,而從新定義模塊時,不會出現模塊名相同致使模塊被覆蓋的狀況。函數
那麼咱們怎麼用這個方法來擴展咱們的命名空間呢?顯然,define和use方法是不能直接使用的,由於咱們的模塊是定義在了工廠方法的參數中,而這兩個方法是被定義在了工廠方法內部中,因此咱們是獲取不到的。oop
那麼讓咱們來改造一下這兩個方法ui
這個出自Vuejs:
var moduleMap = {}; //模塊倉庫 function require(ID){ //參數爲模塊的名字,這裏直接用數字來給模塊定義id if(moduleMap[ID]) //若是模塊已經存在 return moduleMap[ID].exports;//直接返回實例,並結束代碼塊 var module = moduleMap[ID] = { //聲明一個新對象 exports:{},//初始化實例 id:ID, loaded:false//初始化加載狀態 }; modules[ID].call(module.exports, module, module.exports, require); //用call方法將模塊擴展到倉庫中 module.loaded = true; //設置模塊加載狀態 return module.exports; //返回模塊實例 }; return require(0); //返回第一個模塊的調用
這個方法直接把定義模塊的函數放到了工廠方法的參數裏,簡化了不少程序,調用也更方便了。那麼接下來就剩下怎樣將框架模塊與方法註冊到命名空間上了。
這部分咱們放到下一篇來寫。