Seajs模塊化開發Javascript - 用代碼說話(一)

  前言javascript

    模塊化開發JS已經逐漸開始普及,在RequireJS和SeaJS中猶豫了2天,最後選擇從SeaJS入手.網上有很多教程和使用方法,不過理論東西太多了,我是標準的實用主義和拿來主義者,因此直接用代碼說話.
html

  正文前端

    先上一個最簡單的Demo,比官網上的簡單無數倍:
java

    從官網下載最新版本的Sea.js文件,我下載的是2014年3月19的2.2.1版:https://github.com/seajs/seajs/archive/2.2.1.zip.git

    咱們就須要dist中的sea.js便可,接下來在dist文件夾同目錄下建立demo.html,util.js,componet_one.js這三個文件.
github

    util.js文件中定義一個功能,單獨做爲一個模塊:
前端工程師

//util.js
define(function (require,exports,module) {  
    function print (str) {    
    // body...    
    alert(str);  
    }  
    exports.print = print;
});

    而後定義componet_one.js,它的實現依賴於util.js:異步

//componet_one.js
define(function (require,exports,module) {  
    var util = require("./util.js");  
    var ComponetOne = {    
        doSth : function(){      
        util.print("I'm a String.")    
        }  
    }  
    return ComponetOne;
})

    最後在index.html頁面上,直接開始調用:async

<!doctype html>
<html>
    <head>
      <meta charset="UTF-8">
    <title>SeaJS</title>
    </head>
    <body>
      <script type="text/javascript" src="dist/sea.js"></script>
        <script type="text/javascript">
            seajs.use("./componet_one.js",function(componet_one){
                  componet_one.doSth();
            });  
        </script>
    </body>
</html>

    頁面上顯示的結果是彈出一個對話框上面寫着:模塊化

"I'm a String."

    示例完畢,感受如何,我認爲即便對模塊化或者Sea.js和RequireJS一點概念都沒有,只要有必定的Javascript基礎都能理解或者說猜出上面代碼的功能和內容.做爲理解模塊化的入門以及Sea.js應該算是最簡單的代碼了.

    代碼雖少,不過仍是能夠很直觀的看出一些東西的,因此經過這幾段簡單代碼來引入一些Sea.js中的API和使用方法.由於Sea.js遵循的是CommonJS規範,因此它的API使用起來雖然看着和RequireJS很像,但仍是有所不一樣,而且它們內部實現也不同.

    

    (1) CMD模塊定義規範

    在上面的util.js中經過define()定義了一個模塊,能夠看到全局函數define就接受了一個函數參數.其實define還可接受對象或者字符串爲參數,這時表示模塊的接口就是這對象、字符串.

define({"foo" : "bar});
define("It's a template");

    這都是能夠的,大多數的狀況下仍是以函數爲參數,表示模塊的構造方法.執行這個構造方法能夠獲得模塊向外提供的接口,好比上面utils.js中就是如此.這種狀況下方法執行時,默認傳入三個參數:require、exports以及module.

    若是你不知道是否能夠在當前開發項目中使用define,能夠經過define.cmd進行判斷當前頁面是否有CMD模塊加載器:

if (typeof define === "function" && define.cmd){    
    //此時表示存在Sea.js等CMD模塊加載器
}

  

    (2) 經過exports對象向外提供模塊接口

    在util.js中define定義的方法體內,有一行代碼是exports.print = print;什麼都不看的解釋是將方法體內定義的print函數指向exports的print屬性.

    exports是define()定義模塊時,Function傳入的三個默認參數之一,經過它能夠對外提供屬性或者方法.

    除了給exports對象增長成員,也能夠經過return直接向外提供接口,將util.js改成return的方式就以下:

define(function (require,exports,module) {  
    return {   
        print : function(str) {
              // body...      
              alert(str);    
        }
     }
});

    還能夠經過module.exports進行賦值,module是define()的參數爲函數參數時的函數參數的一個函數.這麼說有點費勁,那麼我對以前說的define進行一點補充.

    標準說法的define,應該是define(factory)做爲define的參數,factory可使一個函數,也能夠是一個對象或者字符串.因此說require、exports和module都是factory的默認參數.

    util.js經過module.exports的寫法以下,效果是同樣的:

define(function (require,exports,module) {  
    module.exports =  {   
        print : function(str) {
              // body...
              alert(str);
        }
     }
});

    exports僅僅是module.exports的一個引用,在factory內部給exports從新賦值時,不會改變module.exports的值,所以給exports賦值是沒有效果的,不能用來改變模塊接口.這個地方exports和module.exports的關係和Nodejs中是徹底同樣的.


    (3) 存儲當前模塊屬性和方法的module

     既然上面以及提到了module,這裏就接着往下說,module中最有意義也是須要掌握的就是module.exports,這個在上面說exports的時候提到了.傳給factory構造方法的exports參數是module.exports對象的一個引用.僅僅經過exports參數提供接口有時沒法知足需求.

    例如當模塊的接口是某個類的實例時,就要經過module.exports來實現:

define(function (require,exports,module) {    
    //exports 是 module.exports 的一個引用  
    console.log(module.exports === exports);  //true
    module.exports = new SomeClass();  
    console.log(module.exports === exports);  //false
});

    

    (4) 經過require獲取模塊

    經過define、exports以及module的介紹相信util.js中的代碼是什麼意思並不難理解,而後看一下componet_one.js文件,它也是一個經過define定義的模塊,在factory中第一行:var util = require("./util.js");

    若是以前用過Nodejs,那麼對於require就很熟悉了.它經過一個模塊標識做爲惟一參數,用來獲取模塊提供的接口.這裏就是獲取到了util模塊,可使用util.js文件中定義的內容,這點沒什麼疑問.

    require還有一個實現就是require.async方法用來在模塊內部異步加載模塊,並在加載完成後執行回調函數.

define(function(require,exports,module){    
    //異步加載一個模塊,加載完成後執行callback  
    require.async('./b',function(b){
        b.dosth();
    });
    //異步加載多個模塊,而後執行callback
    require.async(['./c','./d'],function(c,d){
        c.dosth();
        d.dosth();
    });
});

    結尾

        相似RequireJS和SeaJS這類模塊加載器,它們的實質是爲了彌補Javascript在設計之處的不足,能夠想象就連Javascript的發明者也沒有預料到今天Javascript的火熱和普及程度,因此在設計上沒有作好文件組織管理這方面的功能.

    由於早期它看起來確實就是一種簡單的腳本語言,一個頁面也就一個JS文件直接引入就行了.可是隨着Javascript火爆的發展以及大量的應用,這明顯成爲其短板,因此廣大優秀的Coder們想出了各類辦法進行解決.

    模塊加載主要目的是令JavaScript開發模塊化並能夠輕鬆愉悅進行加載,將前端工程師從繁重的JavaScript文件及對象依賴處理中解放出來,能夠專一於代碼自己的邏輯.

        後續會逐漸寫一些更實用的東西,歡迎留言給我,一塊兒學習~

相關文章
相關標籤/搜索