概念
1、為什么要使用模塊化涮较?
- 當代碼規(guī)模較大或進行團隊協(xié)作時稠鼻,如果不實行模塊化,有可能導(dǎo)致命名沖突----解決命名沖突狂票;
- 不使用模塊化的依賴調(diào)用比較容易陷入混亂候齿,使用模塊化有助于依賴的管理----對依賴進行管理;
- 模塊化的代碼更利于他人閱讀和協(xié)同開發(fā)維護----提高代碼可讀性闺属;
- 方便代碼的復(fù)用----代碼解耦慌盯,提高復(fù)用性;
2掂器、CMD润匙、AMD、CommonJS 規(guī)范分別指什么唉匾?有哪些應(yīng)用
2.1孕讳、CMD(Common Module Definition)通用模塊定義規(guī)范
是瀏覽器端的模塊化規(guī)范,是在SeaJS的推廣過程中產(chǎn)生的巍膘,該規(guī)范明確了模塊的基本書寫格式和基本交互規(guī)則厂财,提倡按需加載。
在CMD規(guī)范中峡懈,一個模塊就是一個文件璃饱,代碼格式:
define(id?, deps?, factory)
因為CMD推崇:
1、一個文件一個模塊肪康,所以經(jīng)常就用文件名作為模塊id荚恶;
2、CMD推崇依賴就近磷支,所以一般不在define
的參數(shù)中寫依賴谒撼;
-
define
是一個全局函數(shù),用來定義模塊雾狈; - factory參數(shù)可以是一個函數(shù)廓潜,也可以是一個對象或字符串。
- 當 factory為對象善榛、字符串時辩蛋,表示模塊的接口就是該對象、字符串移盆。
- 當factory為函數(shù)時表示是模塊的構(gòu)造方法悼院。執(zhí)行該構(gòu)造方法可以得到模塊向外提供的接口。factory方法在執(zhí)行時咒循,默認會傳入三個參數(shù):require(把其他模塊導(dǎo)入)据途、exports(把模塊內(nèi)的一些屬性和方法導(dǎo)出) 和 module钮呀。
AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊昨凡;
CMD推崇就近依賴爽醋,只有在用到某個模塊的時候再去require;
//CMD
define(function(require, exports, module){
var a = require('a');
a.doSomething();
var b = require('b');
b.doSomething(); // 依賴就近便脊,延遲執(zhí)行
});
//AMD
define(['a', 'b'], function(a, b){ // 依賴前置蚂四,提前執(zhí)行
a.doSomething();
b.doSomething();
});
明顯看出和 AMD 不同,模塊定義時已不用立馬引入依賴哪痰,而是運行到需要時候再加載遂赠,根據(jù)順序執(zhí)行,這樣更像是 CommonJS 的風格晌杰,讓人感覺也像是同步加載似的跷睦。但實際上 CMD 內(nèi)部處理是對文件做了一個詞法的解析,在還沒執(zhí)行的時候肋演,解析出所需的依賴抑诸,并不是真正的同步。
- CMD規(guī)范的主要應(yīng)用是SeaJS爹殊,現(xiàn)在已經(jīng)被廢棄蜕乡。
2.2、AMD(Asynchronous Module Definition)異步模塊定義規(guī)范
它采用異步方式加載模塊梗夸,模塊的加載不影響它后面語句的運行层玲。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中反症,等到加載完成之后辛块,這個回調(diào)函數(shù)才會運行。
由于不是JS原生支持铅碍,使用AMD規(guī)范進行頁面開發(fā)需要用到對應(yīng)的函數(shù)庫润绵,也就是大名鼎鼎的
RequireJS
,實際上AMD是RequireJS
在推廣過程中對模塊定義的規(guī)范化的產(chǎn)出该酗。RequireJS
主要解決兩個問題
1授药、多個js文件可能有依賴關(guān)系士嚎,被依賴的文件需要早于依賴它的文件加載到瀏覽器呜魄;
2、js加載的時候瀏覽器會停止頁面渲染莱衩,加載文件越多爵嗅,頁面失去響應(yīng)時間越長;例子:
定義模塊myModule.js
// 定義模塊 myModule.js
define(['dependency'], function(){
var name = 'Byron';
function printName(){
console.log(name);
}
return {
printName: printName
};
});
加載模塊
require(['myModule'], function (my){
my.printName();
});
- 語法
1笨蚁、RequireJS
定義了一個函數(shù) define
睹晒,它是全局變量趟庄,用來定義模塊
define(id?, dependencies?, factory);
- id:可選參數(shù),用來定義模塊的標識伪很,如果沒有提供該參數(shù)戚啥,默認就是腳本文件名(去掉拓展名);
- dependencies:是一個當前模塊依賴的模塊名稱數(shù)組锉试;
- factory:工廠方法猫十,模塊初始化要執(zhí)行的函數(shù)或?qū)ο蟆H绻麨楹瘮?shù)呆盖,它應(yīng)該只被執(zhí)行一次拖云。如果是對象,此對象應(yīng)該為模塊的輸出值应又;
2宙项、在頁面上采用require
函數(shù)加載模塊
require([module], callback);
- 第一個參數(shù)
[module]
,是一個數(shù)組株扛,里面的成員就是要加載的模塊尤筐; - 第二個參數(shù)
callback
,則是加載成功之后的回調(diào)函數(shù)洞就。
加載的模塊會以參數(shù)形式傳入該函數(shù)叔磷,從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊;
require()
函數(shù)在加載依賴的函數(shù)的時候是異步加載的奖磁,這樣瀏覽器不會失去響應(yīng)改基,它指定的回調(diào)函數(shù),只有前面的模塊都加載成功后咖为,才會運行秕狰,解決了依賴性的問題。
require(['math'], function(math){
math.add(2, 3);
});
math.add()
與math模塊加載不是同步的躁染,瀏覽器不會發(fā)生假死鸣哀。所以很顯然,AMD比較適合瀏覽器環(huán)境吞彤。
- 實現(xiàn)AMD 規(guī)范的庫有:
require.js我衬、curl.js
和Dojo.js
等。
3.3饰恕、CommonJS通用模塊定義規(guī)范
CommonJS 由首先使用 js模塊化概念的 Node.js采用挠羔,是服務(wù)器端模塊的規(guī)范。
1埋嵌、定義模塊
根據(jù)CommonJS規(guī)范破加,一個單獨的文件就是一個模塊。每一個模塊都是單獨的作用域雹嗦,也就是說范舀,在該模塊內(nèi)部定義的變量合是,無法被其他模塊讀取,除非定義為global對象的屬性锭环。
2聪全、模塊輸出
模塊只有一個出口,module.exports
對象我們需要把模塊希望輸出的內(nèi)容放入該對象辅辩。
3荔烧、加載模塊
加載模塊使用require
方法,該方法讀取一個文件并執(zhí)行汽久,返回文件內(nèi)部的module.exports
對象鹤竭。
例子:
模塊定義 myModel.js
//模塊定義 myModel.js
var name = 'Byron';
function printName(){
console.log(name);
}
function printFullName(firstName){
console.log(firstName + name);
}
module.exports = { //模塊輸出
printName: printName,
printFullName: printFullName
}
加載模塊
var nameModule = require('./myModel.js');
nameModule .printName();
不同的實現(xiàn)對require
時的路徑有不同要求,一般情況可以省略js拓展名景醇,可以使用相對路徑臀稚,也可以使用絕對路徑,甚至可以省略路徑直接使用模塊名(前提是該模塊是系統(tǒng)內(nèi)置模塊)三痰。