咱們已經瞭解到模塊模式是爲單例建立私有變量和特權方法的。
一個最基本的例子:web
var foo=(function(){ var something='cool', var another=[1,2,3]; function dosomething(){ console.log(something); } function doAnother(){ console.log(another.join('!')); } return { doSomething:doSomething, doAnother:doAnother } })(); foo.doSomething(); //cool foo.doAnother(); //1!2!3
咱們將模塊函數轉換成了當即執行函數,當即調用這個函數並將返回值直接賦值給單例的模塊實例標識符。在函數內部定義了私有變量,並經過函數留下了接口,除了經過接口訪問其內部的私有變量的值,在函數外部是沒法訪問它的值的,這也就保證了不會引發命名衝突,修改數據等問題,同時,模塊還能夠複用,大大提升了開發效率。
其實,大多數的模塊倚賴加載器/管理器本質上都是將這種模塊定義封裝進一個友好的API(接口)。咱們知道,在requirejs中,使用define([],function(){})來定一個模塊的,來看下面一段原理性代碼。數組
var MyModules=(function Manager(){ var moudules={}; //對象字面量 function define(name,deps,impl){ for(var i=0;i<deps.length;i++){ deps[i]=moudules[deps[i]]; } moudules[name]=impl.apply(impl,deps); console.log(moudules[name]); } function get(name){ return moudules[name]; } return { define:define, get:get }; })();
這裏咱們定義了一個匿名函數,並讓他當即執行,而後將返回值傳給了MyModules。
接下來咱們執行這樣一段代碼:app
MyModules.define('bar',[],function(){ function hello(who){ return 'Let me introduce:'+who; } return { hello:hello } }); var bar=MyModules.get('bar'); console.log(bar.hello('nihao'));
看一下執行結果:函數
大體分析一下執行過程:
經過MyModules的公共接口define,同時,傳給define的第二個參數是一個空數組,因此說,for循環會跳過,這時,最關鍵的一句是requirejs
impl.apply(impl,deps)
它會將impl也就是第三個匿名函數參數的this值綁定到函數自身的做用域並同時將第二個參數deps做爲函數的參數傳進去。
這時,modules對象中就多了一個bar屬性,其大體的結構跟咱們開篇講的第一個例子,並無什麼兩樣,咱們看一下,其結構:
ui
也就至關於這樣:this
var bar=function(){ function hello(who){ return 'Let me introduce':+who; } return { hello:hello } };
這時,咱們再調用get函數獲取到其屬性,而後調用其hello()方法,結果也就一目瞭然了。code
但這裏,咱們第二個參數是一個空數組,在requirejs中,也就至關於不倚賴任何模塊,那當他須要依賴其餘模塊時,會是什麼樣的狀況呢,他又是如何完成其餘模塊的加載的呢?
咱們在代碼的基礎上,繼續增長以下代碼:對象
MyModules.define('foo',['bar'],function(bar){ var hungry='hippo'; function awesome(){ console.log(bar.hello(hungry).toUpperCase()); } return { awesome:awesome } }); var foo=MyModules.get('foo'); foo.awesome();
看一下其執行結果:blog
是按照咱們預想的那樣輸出的。
咱們再來分析一下執行過程:
其關鍵的步驟就是第二個參數是有一個數組值的數組,代碼將執行遍歷此數組操做,而後,將該數組的第一個值賦值爲此前module對象中的bar屬性對象,因此說該數組中的值也就也就指向了moudule對象中的bar屬性對象(注意引用類型的複製問題)。
其也就當作參數傳遞到了modules對象的另一個屬性foo之中,其實,這也就完成了requirejs中加載模塊的功能。這時,當咱們引用bar模塊中的公共接口的時候,其結果也就在情理之中了。
其實,這段代碼的核心就是modules[name]=impl.apply(impl,deps)。爲了模塊的定義引入了包裝函數(能夠傳入任何依賴),並將其返回值,也就是模塊的API,存儲在一個根據名字來管理的模塊列表中。
以上內容,純屬我的理解,若是有不對之處,還請你們熱心指正。