javascript模塊化

我們?yōu)槭裁匆K化?
一般出來什么東西,說明當(dāng)前的工具有其缺陷,或者是為了方便什么。
那么我們就來看看通過模塊,我們可以做到什么?
我們可以只關(guān)注自己的核心邏輯,而不用考慮其中的輔助功能。比如我們想要實現(xiàn)計算兩個文本框中數(shù)值的和,我們只需要關(guān)注業(yè)務(wù)邏輯,而不需要關(guān)注自己如何查找到該元素(查找到元素可以交給jquery來做,還解決了兼容性問題)。
通過模塊,我們可以方便的使用別人的代碼,需要什么模塊就引入對應(yīng)的依賴模塊。

我們先來看看幾種原生js的實現(xiàn)模塊化得方法(下面說的每一個方法都是為了解決上一種方法出現(xiàn)的問題):

  • 原始的模塊寫法:

        function a1(){
    
        }
    
        function a2(){
    
        }
      缺點:污染全局變量,可能造成變量沖突,無法直觀的顯示二者的聯(lián)系
    
  • 解決上一問題

var module = {
    a1: function(){
    
    },
    a2: function(){
    
    }
}
缺點:用戶可以在外面修改module內(nèi)的變量
  • 解決上一問題
var module = (function(){
    var m1 = function(){
    };
    var m2 = function(){
    };

    return {
        m1 : m1,
        m2 : m2
    };
});
通過立即執(zhí)行函數(shù),這樣就解決了模塊內(nèi)部變量可能被修改的問題
缺點: 如果此模塊需要依賴另一個模塊才能生效
  • 解決上一問題
var module = (function(mod){
    mod.m1 = function(){
    };
    return mod;
})(another_module);

下面我們介紹現(xiàn)在應(yīng)用廣泛的javascript模塊規(guī)范:CommonJS,AMD,以及國內(nèi)的CMD。

  1. CommonJS
    我們先來說CommonJS,在其中有一個require()方法,用于加載模塊
    比如:
    假設(shè)我們的一個模塊(add_module)中有一個求兩數(shù)之和的方法,在另一個地方我們就可以通過下面的方法使用這個求和方法。
var addModule = require(‘a(chǎn)dd_module’);
addModule.add(1,2);
  1. AMD
    既然已經(jīng)有了CommonJS,為什么還會出現(xiàn)AMD呢?
因為CommonJS不適合瀏覽器環(huán)境,上面的代碼假如在瀏覽器中執(zhí)行,那么瀏覽器需要時間來加載add_module,如果網(wǎng)絡(luò)條件不好,瀏覽器會出現(xiàn)“假死”狀態(tài)。因此瀏覽器端不能采用“同步加載”,而應(yīng)該使用“異步加載”。

AMD(異步模塊定義),采用異步的方式加載模塊,所有需要依賴其他模塊的語句都被定義在回調(diào)函數(shù)中。
用AMD的語法改寫上面CommonJS的寫法:

require([‘a(chǎn)dd_module’],function(addModule){
    addModule.add(1,2);
});
  1. 基于AMD規(guī)范的javascript庫:require.js
    require.js是為了實現(xiàn)下面的兩個效果:
  • 實現(xiàn)js文件的異步加載,避免網(wǎng)頁失去響應(yīng);
  • 管理模塊之間的依賴性,便于代碼的編寫和維護。

3.1 使用require.js
從官網(wǎng)下載require.js,在html中引入

<script src="js/require.js" defer async="true" ></script>

async屬性表明這個文件需要異步加載,避免網(wǎng)頁失去響應(yīng)。IE不支持這個屬性,只支持defer,所以把defer也寫上。
引入我們自己寫的需要執(zhí)行的js文件

<script src="js/require.js" data-main=“main” defer async="true" ></script>

data-main屬性的作用是,指定網(wǎng)頁程序的主模塊。在上例中,就是js目錄下面的main.js,這個文件會第一個被require.js加載。由于require.js默認的文件后綴名是js,所以可以把main.js簡寫成main。

  main.js文件:
require(['moduleA', 'moduleB'], function (moduleA, moduleB){
    // some code here
  });

require()函數(shù)接受兩個參數(shù)。第一個參數(shù)是一個數(shù)組,表示所依賴的模塊,上例就是['moduleA', 'moduleB'],即主模塊依賴這2個模塊;第二個參數(shù)是一個回調(diào)函數(shù),當(dāng)前面指定的模塊都加載成功后,它將被調(diào)用。加載的模塊會以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊。
require()異步加載moduleA,moduleB,瀏覽器不會失去響應(yīng);它指定的回調(diào)函數(shù),只有前面的模塊都加載成功后,才會運行,解決了依賴性的問題。

比如我們需要依賴jquery
require(['jquery'], function ($){
    // some code here
  });

  主模塊的依賴模塊是['jquery']。
默認情況下,require.js假定這個模塊與main.js在同一個目錄,文件名為jquery.js,然后自動加載。
使用require.config()方法,我們可以對模塊的加載行為進行自定義。require.config()就寫在主模塊(main.js)的頭部。
參數(shù)就是一個對象,這個對象的paths屬性指定各個模塊的加載路徑。
如果我們的依賴文件和main.js不在同一文件夾下呢?
require.config({
    paths: {
      "jquery": "lib/jquery.min"
    }
  });
也可以通過配置baseUrl來改變基目錄
require.config({
    baseUrl: "js/lib",
    paths: {
      "jquery": "jquery.min"
    }
  });
自定義的require.js加載的模塊,采用AMD規(guī)范,即就是模塊必須采用特定的define()函數(shù)來定義。
  • 如果一個模塊不依賴其他模塊,那么可以直接定義在define()函數(shù)之中。
define(function (){
    var add = function (x,y){
      return x+y;
    };
    return {
      add: add
    };
  });
  • 如果這個模塊還依賴其他模塊,那么define()函數(shù)的第一個參數(shù),必須是一個數(shù)組,指明該模塊的依賴性。
define(['myLib'], function(myLib){
    function foo(){
      myLib.doSomething();
    }
    return {
      foo : foo
    };
  });
加載非規(guī)范的模塊

理論上,require.js加載的模塊,必須是按照AMD規(guī)范、用define()函數(shù)定義的模塊。但是實際上,雖然已經(jīng)有一部分流行的函數(shù)庫(比如jQuery)符合AMD規(guī)范,更多的庫并不符合。那么,require.js是否能夠加載非規(guī)范的模塊呢?
回答是可以的。
這樣的模塊在用require()加載之前,要先用require.config()方法,定義它們的一些特征。
舉例來說,underscore和backbone這兩個庫,都沒有采用AMD規(guī)范編寫。如果要加載它們的話,必須先定義它們的特征。

  require.config({
    shim: {
      'underscore':{
        exports: '_'
      },
      'backbone': {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      }
    }
  });

require.config()接受一個配置對象,這個對象除了有前面說過的paths屬性之外,還有一個shim屬性,專門用來配置不兼容的模塊。具體來說,每個模塊要定義(1)exports值(輸出的變量名),表明這個模塊外部調(diào)用時的名稱;(2)deps數(shù)組,表明該模塊的依賴性。

4.CMD
關(guān)于CMD的介紹,大家可以點擊這里查看;
關(guān)于AMD和CMD的比較,大家可以點擊這里看玉伯寫的一篇評論;
SeaJS和RequireJS的區(qū)別,大家可以點擊這里

本文內(nèi)容是我自己在阮一峰博客的基礎(chǔ)上整理的,原文大家可以查看:
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_definition.html
http://www.ruanyifeng.com/blog/2012/11/require_js.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內(nèi)容