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(){
    
        }
      缺點(diǎn):污染全局變量樊零,可能造成變量沖突,無法直觀的顯示二者的聯(lián)系
    
  • 解決上一問題

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

    return {
        m1 : m1,
        m2 : m2
    };
});
通過立即執(zhí)行函數(shù)孽文,這樣就解決了模塊內(nèi)部變量可能被修改的問題
缺點(diǎn): 如果此模塊需要依賴另一個模塊才能生效
  • 解決上一問題
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)旬昭;
  • 管理模塊之間的依賴性,便于代碼的編寫和維護(hù)菌湃。

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默認(rèn)的文件后綴名是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ù)盐欺,只有前面的模塊都加載成功后赁豆,才會運(yùn)行,解決了依賴性的問題冗美。

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

  主模塊的依賴模塊是['jquery']魔种。
默認(rèn)情況下,require.js假定這個模塊與main.js在同一個目錄粉洼,文件名為jquery.js节预,然后自動加載。
使用require.config()方法属韧,我們可以對模塊的加載行為進(jìn)行自定義安拟。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的介紹,大家可以點(diǎn)擊這里查看自娩;
關(guān)于AMD和CMD的比較用踩,大家可以點(diǎn)擊這里看玉伯寫的一篇評論;
SeaJS和RequireJS的區(qū)別忙迁,大家可以點(diǎn)擊這里脐彩。

本文內(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閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梗掰,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗅回,警方通過查閱死者的電腦和手機(jī)及穗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绵载,“玉大人埂陆,你說我怎么就攤上這事⊥薇” “怎么了焚虱?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長懂版。 經(jīng)常有香客問我鹃栽,道長,這世上最難降的妖魔是什么躯畴? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任谍咆,我火速辦了婚禮,結(jié)果婚禮上私股,老公的妹妹穿的比我還像新娘。我一直安慰自己恩掷,他們只是感情好倡鲸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著黄娘,像睡著了一般峭状。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逼争,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天优床,我揣著相機(jī)與錄音,去河邊找鬼誓焦。 笑死胆敞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杂伟。 我是一名探鬼主播移层,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赫粥!你這毒婦竟也來了观话?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤越平,失蹤者是張志新(化名)和其女友劉穎频蛔,沒想到半個月后灵迫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晦溪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年瀑粥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尼变。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡利凑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嫌术,到底是詐尸還是另有隱情哀澈,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布度气,位于F島的核電站割按,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏磷籍。R本人自食惡果不足惜适荣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望院领。 院中可真熱鬧弛矛,春花似錦、人聲如沸比然。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽强法。三九已至万俗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饮怯,已是汗流浹背闰歪。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蓖墅,地道東北人库倘。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像置媳,于是被迫代替她去往敵國和親于樟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

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