概念
JavaScript語言本身是沒有模塊化的概念的,但是我們可以借助requirejs這個(gè)模塊化工具,實(shí)現(xiàn)js代碼的模塊化。requirejs的作用,就是將項(xiàng)目中的代碼,都寫成模塊化的東西,模塊之間又可以相互依賴,讓整個(gè)項(xiàng)目的可讀性,可維護(hù)性變得更好,同時(shí)又減少了全局污染。
在使用requirejs之前,最好了解一下AMD(異步模塊定義)規(guī)范和CMD規(guī)范。我在學(xué)習(xí)之前并沒有去了解他們之間的區(qū)別,導(dǎo)致我在學(xué)習(xí)的過程中非常懵。
AMD規(guī)范:https://github.com/amdjs/amdjs-api/wiki/AMD
CMD規(guī)范:https://github.com/seajs/seajs/issues/242
目前遵循AMD規(guī)范的就是RequireJs,而CMD規(guī)范對應(yīng)的有SeaJs,但AMD規(guī)范在寫法上也是支持CMD的一些寫法的,在這里糾結(jié)了一點(diǎn)時(shí)間,后邊提。
為什么要使用RequireJs
我們在網(wǎng)頁中,如果需要加載很的js文件,傳統(tǒng)的寫法是:
<script src="1.js"></script>
<script src="2.js"></script>
......
在加載js文件的時(shí)候,瀏覽器會(huì)停止渲染,將需要加載的文件變得非常多時(shí),瀏覽器可能就停止響應(yīng)。其次,當(dāng)一個(gè)a.js文件依賴于另一個(gè)b.js文件的時(shí)候,需要將b.js文件放在前面,先于a.js加載,當(dāng)依賴增多時(shí),要處理起來就會(huì)很復(fù)雜。
RequireJs就是為了解決這些問題的。
一、如何引入RequireJs
去官網(wǎng)下載http://www.requirejs.org/后,假如將require.js文件放在與index.html同級(jí)目錄的情況下,index.html的script標(biāo)簽按如下方式引入:
<script src="./require.js" defer async="true"></script>
async表示這個(gè)也使用異步加載,避免在加載它的時(shí)候,網(wǎng)頁失去響應(yīng),ie瀏覽器不支持,所以,加個(gè)defer屬性。
要使用requirejs加載文件,使用data-main屬性指定入口文件main.js:
<script src="./require.js" data-main="main.js"></script>
二、使用
配置規(guī)則
在main.js中,需要指定一些requirejs的配置規(guī)則,使用require.config()方法,我們可以對requirejs的規(guī)則配置,這個(gè)方法以對象的方式接收配置屬性。
baseUrl定義加載文件的基準(zhǔn)目錄,如果不指定的情況下,默認(rèn)加載上述的index.html所在的目錄為根目錄。
path屬性保存模塊的鍵/值,其中key是模塊的名稱,value則是模塊的地址,不需要添加.js后綴。該地址會(huì)與baseuUrl中的基準(zhǔn)目錄進(jìn)行拼接,所以,如果不需要拼接的話,使用"/"、“https://”、".js"來規(guī)避與baseUrl的拼接規(guī)則。
require.config({
? ? baseUrl: "./js",
? ? path: {
? ? ? ? jquery: "http://xxx.xxxx.com/js/jquery.min",
? ? ? ? hello: "hello"
????}
})
配置規(guī)則的引入方式
requirejs的配置文件有兩種方式,一是以<script>標(biāo)簽內(nèi)嵌到html文件中,另一種則是以js文件加載的方式獨(dú)立引入。
而獨(dú)立引入的方式也有兩種
以js標(biāo)簽加載外部文件引入:
<script src="require.js"></script>
<script src="config.js"></script>
以data-main屬性引入,通過data-main去加載入口文件,會(huì)使得baseUrl指向config.js所在文件的目錄。
<script data-main="config.js" src=“require.js”></script>
當(dāng)你的項(xiàng)目足夠大時(shí),推薦將入口文件單獨(dú)配置成一個(gè)模塊,根據(jù)不同的業(yè)務(wù)去加載不同的配置文件:

RequireJs常用的命令是define和require,define定義模塊,require引入模塊。
define格式如下
define(id?, dependencies?, factory)
id是模塊的名字,是一個(gè)可選參數(shù)
dependencies是該模塊的依賴元素,指定所依賴的列表,是一個(gè)數(shù)組元素??梢宰鳛閰?shù)傳遞到factory函數(shù)中去,當(dāng)沒有指定依賴的話,默認(rèn)是“require”,"exports","module"。
require格式如下:
require(array,function)
array是依賴的對象的數(shù)組,function是一個(gè)回調(diào)函數(shù),在依賴加載完成后執(zhí)行。比如,我們可以通過
require("app",function(app) {
? ? app.method()
})
來引入app模塊,并執(zhí)行app模塊里邊的方法。對于依賴的模塊,AMD推薦依賴前置,CMD推薦依賴就近,依賴前置如下,提前加載好所需要的依賴:

下圖采用的是依賴就近的模式,在需要使用的地方,通過require加載對應(yīng)的模塊。

在AMD中,是支持依賴就近的寫法的,所以,requirejs中,以上兩種方式都能執(zhí)行。但是,requirejs官方文檔中,默認(rèn)都是采用依賴前置的寫法。
你可能可以注意到,define和require這2個(gè)api,都可以引入依賴模塊,那他們的區(qū)別在哪里呢?
define定義的模塊可以以return或者export的方式,返回一個(gè)模塊對象供別的模塊調(diào)用,而require不需要返回對象。
說道這個(gè)return,那么,define的模塊是以什么方式返回模塊對象呢?請看下邊的模塊返回值。
模塊的返回值
return方式
// 在helo.js中這樣子定義一個(gè)模塊,并返回一個(gè)函數(shù)
define(function(require, exports, modules) {
? ? var sayHello = function(params) {
????????console(params)
}
? ? return sayHello
})
// 在index.js中,引入helo.js并運(yùn)行里邊的方法
define(function(require, exports, module) {
? ? ? ? var sayHello = require("helo")
? ? ? ? sayHello.sayHello("hello")
})
exports方式
// 在helo.js中這樣子定義一個(gè)模塊,并通過exports返回一個(gè)函數(shù)
define(function(require, exports, module) {
? ? exports.sayHello = function(params) {
? ? ? ? consloe.log(params)
????}
})
// 在index.js中,引入helo.js并運(yùn)行里邊的方法
define(function(require, exports, module) {
? ? ? ? var sayHello = require("helo")
? ? ? ? sayHello.sayHello("hello")
})