關於requirejs中的define的原理理解

咱們已經瞭解到模塊模式是爲單例建立私有變量和特權方法的。
一個最基本的例子: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'));

看一下執行結果:enter description here函數

大體分析一下執行過程:
經過MyModules的公共接口define,同時,傳給define的第二個參數是一個空數組,因此說,for循環會跳過,這時,最關鍵的一句是requirejs

impl.apply(impl,deps)

它會將impl也就是第三個匿名函數參數的this值綁定到函數自身的做用域並同時將第二個參數deps做爲函數的參數傳進去。
這時,modules對象中就多了一個bar屬性,其大體的結構跟咱們開篇講的第一個例子,並無什麼兩樣,咱們看一下,其結構:
enter description hereui

也就至關於這樣: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();

看一下其執行結果:enter description hereblog

是按照咱們預想的那樣輸出的。
咱們再來分析一下執行過程:
其關鍵的步驟就是第二個參數是有一個數組值的數組,代碼將執行遍歷此數組操做,而後,將該數組的第一個值賦值爲此前module對象中的bar屬性對象,因此說該數組中的值也就也就指向了moudule對象中的bar屬性對象(注意引用類型的複製問題)。
其也就當作參數傳遞到了modules對象的另一個屬性foo之中,其實,這也就完成了requirejs中加載模塊的功能。這時,當咱們引用bar模塊中的公共接口的時候,其結果也就在情理之中了。

其實,這段代碼的核心就是modules[name]=impl.apply(impl,deps)。爲了模塊的定義引入了包裝函數(能夠傳入任何依賴),並將其返回值,也就是模塊的API,存儲在一個根據名字來管理的模塊列表中。

以上內容,純屬我的理解,若是有不對之處,還請你們熱心指正。

相關文章
相關標籤/搜索