模塊化開發(fā)

前端JS模塊化開發(fā)有兩大規(guī)范AMD合CMD寻定,下面以我的理解來簡單總結(jié)一下模塊化開發(fā)的思想 ,以及js前端常用的AMD和CMD 的區(qū)別,AMD代表是requireJs(異步加載),CMD代表seaJs酥夭。

一,模塊化的誕生

? ? 當(dāng)一個項目開發(fā)的越來越復(fù)雜的時候,就會出現(xiàn)一些命名沖突糊肤,或者文件依賴(后一個js必須依賴前一個js文件)等問題,所以需要進(jìn)行模塊化開發(fā)苔悦,來提升開發(fā)效率轩褐,以及方面后期維護(hù)。

二玖详,模塊化開發(fā)的演變

1.全局函數(shù)

? ? ? ? 寫法:

缺點(diǎn):1.污染全局變量,不能阻止變量命名沖突? 2.模塊之間看不出聯(lián)系

2.對象封裝

寫法

缺點(diǎn):1,暴露了所有成員勤讽,內(nèi)部對象可以被篡改蟋座,不安全 2.一定程度上解決了變量沖突,但是命名空間會越來越長

3脚牍,私有公有成員分離

寫法

優(yōu)點(diǎn): 1.利用閉包將函數(shù)包裝成一個獨(dú)立的作用域向臀,私有空間的變量和函數(shù)不會影響全局作用域? 2,以返回值的方式可以有選擇的對外暴漏公用方法诸狭,隱藏私有方法和變量? ? ?3券膀,一定意義上解決了命名沖突

4,模塊的擴(kuò)展與維護(hù)


優(yōu)點(diǎn): 1.有利于對龐大模塊的子模塊擴(kuò)展? 2.實(shí)現(xiàn)開閉原則:對新增模塊開放驯遇,對修改關(guān)閉

5.第三方依賴介入


原則:高內(nèi)聚低耦合芹彬,模塊內(nèi)相關(guān)性高,模塊間關(guān)聯(lián)低叉庐。

三舒帮,模塊化規(guī)范

服務(wù)器端規(guī)范主要是CommonJSnode.js用的就是CommonJS規(guī)范陡叠。

客戶端規(guī)范主要有:AMD(異步模塊定義玩郊,推崇依賴前置)、CMD(通用模塊定義枉阵,推崇依賴就近)译红。AMD規(guī)范的實(shí)現(xiàn)主要有RequireJSCMD規(guī)范的主要實(shí)現(xiàn)有SeaJS兴溜。RequireJS在國外用的比較多侦厚,SeaJS在國內(nèi)用的比較多反璃,并且SeaJS的創(chuàng)始人為阿里的玉伯,所以SeaJS在阿里系用的非常廣泛假夺,包括京東等大廠也在用SeaJS淮蜈,我們詳細(xì)介紹的也是SeaJS。但是SeaJS已經(jīng)停止維護(hù)了已卷,因為在ES6中已經(jīng)有了模塊化的實(shí)現(xiàn)梧田,隨著ES6的普及,第三方的模塊化實(shí)現(xiàn)將會慢慢的淘汰(但是這個在國內(nèi)可能還要很多年)侧蘸。

四裁眯,seaJs

1.用法

(1)引入seajs

(2)定義模塊:define(function(require, exports, module){ 模塊代碼 });? ??require(‘模塊id’)? ?輸出內(nèi)容: exports.add = add;? 用法: sea.usa("id",function(模塊對象){業(yè)務(wù)代碼});

(3)實(shí)際應(yīng)用

在a.js內(nèi)寫cmd模塊化規(guī)范代碼如下


在index.html的應(yīng)用


2. 定義模塊define

先有規(guī)范,后有實(shí)現(xiàn)

在CMD規(guī)范中讳癌,一個模塊就是一個js文件

define是一個全局函數(shù)穿稳,用來定義模塊

define(factory)

對象{}這種方式,外部會直接獲取到該對象

字符串''同上

函數(shù)function( require, exports, module ){ // 模塊代碼 }

注意:為了減少出錯晌坤,定義函數(shù)的時候直接把這三個參數(shù)寫上

factory為對象逢艘、字符串時,表示模塊的接口就是該對象骤菠、字符串它改。比如可以如下定義一個 JSON 數(shù)據(jù)模塊:

define({"foo":"bar"});

也可以通過字符串定義模板模塊:

define('I am a template. My name is {{name}}.');

factory為函數(shù)時,表示是模塊的構(gòu)造方法商乎。執(zhí)行該構(gòu)造方法央拖,可以得到模塊向外提供的接口。factory方法在執(zhí)行時鹉戚,默認(rèn)會傳入三個參數(shù):require鲜戒、exports和 module:

define(function(require, exports, module){// 模塊代碼});

define define(id?, deps?, factory)

define也可以接受兩個以上參數(shù)。字符串 id表示模塊標(biāo)識抹凳,數(shù)組 deps是模塊依賴遏餐。比如:

define('hello', ['jquery'],function(require, exports, module){// 模塊代碼});

id和 deps參數(shù)可以省略。省略時却桶,可以通過構(gòu)建工具自動生成境输。

注意:帶 id和 deps參數(shù)的 define用法不屬于 CMD 規(guī)范,而屬于Modules/Transport規(guī)范颖系。

define.cmdObject

一個空對象嗅剖,可用來判定當(dāng)前頁面是否有 CMD 模塊加載器:

if(typeofdefine ==="function"&& define.cmd) {// 有 Sea.js 等 CMD 模塊加載器存在}

requireFunction

require是 factory函數(shù)的第一個參數(shù)。

requirerequire(id)

require是一個方法嘁扼,接受模塊標(biāo)識作為唯一參數(shù)信粮,用來獲取其他模塊提供的接口。

define(function(require, exports){// 獲取模塊 a 的接口 vara =require('./a');// 調(diào)用模塊 a 的方法 a.doSomething();});

注意:在開發(fā)時趁啸,require的書寫需要遵循一些簡單約定强缘。

require.async

require.async方法用來在模塊內(nèi)部異步加載模塊督惰,并在加載完成后執(zhí)行指定回調(diào)。callback參數(shù)可選旅掂。

define(function(require, exports, module){// 異步加載一個模塊赏胚,在加載完成時,執(zhí)行回調(diào)require.async('./b',function(b){? ? b.doSomething();? });// 異步加載多個模塊商虐,在加載完成時觉阅,執(zhí)行回調(diào)require.async(['./c','./d'],function(c, d){? ? c.doSomething();? ? d.doSomething();? });});

注意:require是同步往下執(zhí)行,require.async則是異步回調(diào)執(zhí)行秘车。require.async 一般用來加載可延遲異步加載的模塊典勇。

require.resolverequire.resolve(id)

使用模塊系統(tǒng)內(nèi)部的路徑解析機(jī)制來解析并返回模塊路徑。該函數(shù)不會加載模塊叮趴,只返回解析后的絕對路徑割笙。

define(function(require, exports){console.log(require.resolve('./b'));// ==> http://example.com/path/to/b.js});

這可以用來獲取模塊路徑,一般用在插件環(huán)境或需動態(tài)拼接模塊路徑的場景下眯亦。

4. exports 和 module.exports

功能:通過給 exports或module.exports動態(tài)的掛載變量伤溉、函數(shù)或?qū)ο?外部會獲取到該接口

exports 等價于 module.exports

可以通過多次給exports 掛載屬性向外暴露

不能直接給 exports 賦值

如果想暴露單個變量、函數(shù)或?qū)ο罂梢酝ㄟ^直接給module.exports 賦值 即可

5. exports

exports是一個對象搔驼,用來向外提供模塊接口谈火。

define(function(require, exports){// 對外提供 foo 屬性exports.foo ='bar';// 對外提供 doSomething 方法exports.doSomething =function(){};});

除了給 exports對象增加成員,還可以使用 return直接向外提供接口舌涨。

define(function(require){// 通過 return 直接提供接口return{foo:'bar',doSomething:function(){}? };});

如果 return語句是模塊中的唯一代碼,還可簡化為:

define({foo:'bar',? doSomething:function() {}});

上面這種格式特別適合定義 JSONP 模塊扔字。

特別注意:下面這種寫法是錯誤的囊嘉!

define(function(require, exports){// 錯誤用法!革为!!exports = {foo:'bar',doSomething:function(){}? };});

正確的寫法是用 return或者給 module.exports賦值:

define(function(require, exports, module){// 正確寫法module.exports = {foo:'bar',doSomething:function(){}? };});

提示:exports 僅僅是 module.exports 的一個引用扭粱。在 factory 內(nèi)部給 exports 重新賦值時,并不會改變 module.exports 的值震檩。因此給 exports 賦值是無效的琢蛤,不能用來更改模塊接口。

6. moduleObject

module是一個對象抛虏,上面存儲了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法博其。

6.1 module.idString

模塊的唯一標(biāo)識。

define('id', [],function(require, exports, module){// 模塊代碼});

上面代碼中迂猴,define的第一個參數(shù)就是模塊標(biāo)識慕淡。

6.2 module.uriString

根據(jù)模塊系統(tǒng)的路徑解析規(guī)則得到的模塊絕對路徑。

define(function(require, exports, module){console.log(module.uri);// ==> http://example.com/path/to/this/file.js});

一般情況下(沒有在 define 中手寫 id 參數(shù)時)沸毁,module.id 的值就是 module.uri峰髓,兩者完全相同傻寂。

6.3 module.dependenciesArray

dependencies是一個數(shù)組,表示當(dāng)前模塊的依賴携兵。

6.4 module. exportsObject

當(dāng)前模塊對外提供的接口疾掰。

傳給 factory 構(gòu)造方法的 exports 參數(shù)是 module.exports 對象的一個引用。只通過 exports 參數(shù)來提供接口徐紧,有時無法滿足開發(fā)者的所有需求静檬。 比如當(dāng)模塊的接口是某個類的實(shí)例時,需要通過 module.exports 來實(shí)現(xiàn):

define(function(require,exports,module) {// exports 是 module.exports 的一個引用console.log(module.exports===exports);// true// 重新給 module.exports 賦值module.exports=newSomeClass();// exports 不再等于 module.exportsconsole.log(module.exports===exports);// false});

注意:對 module.exports 的賦值需要同步執(zhí)行浪汪,不能放在回調(diào)函數(shù)里巴柿。下面這樣是不行的:

// x.jsdefine(function(require, exports, module){// 錯誤用法setTimeout(function(){module.exports = {a:"hello"};? },0);});

在 y.js 里有調(diào)用到上面的 x.js:

// y.jsdefine(function(require, exports, module){varx =require('./x');// 無法立刻得到模塊 x 的屬性 aconsole.log(x.a);// undefined});

7. 小結(jié)

這就是 CMD 模塊定義規(guī)范的所有內(nèi)容。經(jīng)常使用的 API 只有 define, require, require.async, exports, module.exports 這五個死遭。其他 API 有個印象就好广恢,在需要時再來查文檔,不用刻意去記呀潭。

與 RequireJS 的 AMD 規(guī)范相比钉迷,CMD 規(guī)范盡量保持簡單,并與 CommonJS 和 Node.js 的 Modules 規(guī)范保持了很大的兼容性钠署。通過 CMD 規(guī)范書寫的模塊糠聪,可以很容易在 Node.js 中運(yùn)行

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谐鼎,隨后出現(xiàn)的幾起案子舰蟆,更是在濱河造成了極大的恐慌,老刑警劉巖狸棍,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件身害,死亡現(xiàn)場離奇詭異,居然都是意外死亡草戈,警方通過查閱死者的電腦和手機(jī)塌鸯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唐片,“玉大人丙猬,你說我怎么就攤上這事》丫拢” “怎么了茧球?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長揽思。 經(jīng)常有香客問我袜腥,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任羹令,我火速辦了婚禮鲤屡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘福侈。我一直安慰自己酒来,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布肪凛。 她就那樣靜靜地躺著堰汉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伟墙。 梳的紋絲不亂的頭發(fā)上翘鸭,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天,我揣著相機(jī)與錄音戳葵,去河邊找鬼就乓。 笑死,一個胖子當(dāng)著我的面吹牛拱烁,可吹牛的內(nèi)容都是我干的生蚁。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼戏自,長吁一口氣:“原來是場噩夢啊……” “哼邦投!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起擅笔,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤志衣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后猛们,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蠢涝,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年阅懦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徘铝。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡耳胎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惕它,到底是詐尸還是另有隱情怕午,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布淹魄,位于F島的核電站郁惜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏甲锡。R本人自食惡果不足惜兆蕉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一羽戒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虎韵,春花似錦易稠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至测萎,卻和暖如春亡电,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背硅瞧。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工份乒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人零酪。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓冒嫡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親四苇。 傳聞我的和親對象是個殘疾皇子孝凌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351

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