js的模塊化探究

這篇文章觀點(diǎn)主要來源阮一峰的博客及自己的理解,這里寫出來一是為了加強(qiáng)自己的記憶,二是希望和大家一起分享,如果有錯誤希望大家指出。
模塊通俗來說就是包含有很多方法的集合,感覺有點(diǎn)像別的語言中的庫文件,在網(wǎng)頁應(yīng)用中JavaScript的使用越來越廣泛,一個網(wǎng)頁中所用到的js文件也越來越多,管理起這些文件就顯得非?;靵y,首先看看js的模塊化寫法,

js的模塊化

如果將所有方法都直接寫在全局域里面,那么就會污染全局變量,甚至占用很多有用的名字,取名也會費(fèi)一番腦經(jīng),這種方式很不適合大型開發(fā)

function f1(){
//...
}
function f2(){
//...
}
//...

改進(jìn)的寫法就是將這些方法寫入一個對象中,但是如果模塊里面有一些不希望暴露給使用者的屬性或方法,就沒有辦法了

var module=new Obeject(
f:1,//不希望給外面調(diào)用
f1:function(){
//...
},
f2:function(){
//...
},
//...
);

這就出現(xiàn)了立即執(zhí)行函數(shù)這種寫法,這個函數(shù)返回一個希望暴露給外部的一系列方法或?qū)傩缘膶ο蠹希ㄉ踔吝€可以用新的名字去替換原先模塊里的名字),并直接定義一個變量去引用這個對象

var module1=(function(){
f:1,//不希望給外面調(diào)用
var f1=function(){
//...
}
var f1=function(){
//...
},
//...
return {
out_f1:f1,
out_f2:f2
};
})();

這里將f這個屬性向外界隱藏了,這種方式還可以對function傳入其他全局變量甚至傳入它自己,用以分次添加模塊的方法,可以很方便的臨時添加功能

//傳入其他全局變量,比如類庫
var module2=(fuction($,mod,mod1){
//使用jquery操作等
mod.f3=mod1.dosomething;//將別的模塊的方法添加到這里來
return mod;//返回修改后的module2
})(Jquery,module2,module3)

現(xiàn)行的模塊規(guī)范有兩種,一種是CommonJs,另一個是AMD。
由于nodejs的出現(xiàn),讓JavaScript不再局限于網(wǎng)頁端編程,進(jìn)入了服務(wù)器的領(lǐng)域,對于復(fù)雜的后端邏輯避免不了大量的模塊引用,在nodejs中,模塊是采用CommonJs的規(guī)范寫的,使用下面的方式去加載和使用一個寫好的math模塊

var math = require('math');
math.add(2,3); // 5

這種方式在瀏覽器環(huán)境中是不適合的,要使用這個模塊的方法必須等這個加載過程結(jié)束才可以,模塊存儲在服務(wù)器端,從瀏覽器端加載模塊會因?yàn)楦鞣N各樣的原因?qū)е录虞d緩慢,這樣頁面就會停滯,這會大大影響用戶的體驗(yàn)。
因此在瀏覽器端不適合同步加載,必須使用異步加載,于是AMD規(guī)范出現(xiàn)了,AMD是"Asynchronous Module Definition"的縮寫,意思就是“異步模塊定義”。 它采用的也是require方法去加載模塊,但是它的參數(shù)帶有一個回調(diào)函數(shù),也就是加載成功就會執(zhí)行那個函數(shù)

require([module], callback);//兩個參數(shù),一個模塊名,一個回調(diào)函數(shù)
require(['math'], function (math) {
math.add(2, 3);
});

現(xiàn)在主要有兩個Javascript庫實(shí)現(xiàn)了AMD規(guī)范:require.jscurl.js。

require.js的使用

最早的時候,js文件只需要幾個就夠了,js文件之間的依賴關(guān)系也沒有那么密切,然而現(xiàn)在的情況不同了,經(jīng)常會見到下面的代碼

<script src="1.js"></script> 
<script src="2.js"></script>
<script src="3.js"></script>
<script src="4.js"></script>
<script src="5.js"></script>
<script src="6.js"></script>

相互之間還會有依賴關(guān)系,比如很多js文件都很依賴jquery這個庫,所以如果加載順序不同,會很麻煩,因此要嚴(yán)格遵照依賴性順序,依賴性最大的放到最后,require.js的出現(xiàn)主要是為了兩個問題,一是實(shí)現(xiàn)異步加載js文件,防止網(wǎng)頁失去響應(yīng),二是為了管理模塊之間的依賴關(guān)系,方便編寫和維護(hù)。
和別的js模塊一樣,要使用它首先要去官網(wǎng)下載一個最新的版本,加載這個文件時可能也會讓網(wǎng)頁失去反應(yīng),可以在網(wǎng)頁的最后面去加載,也可以使用下面的方式加載

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

其中defer是為了支持IE,它不支持async屬性,這樣就可以異步加載這個js文件了,這樣只是加載了require.js,還要給data-main屬性寫一個入口文件,制定網(wǎng)頁程序的主模塊

<script src="js/require.js" data-main="js/main"></script>

其中main.js就是我們的主模塊,假設(shè)也是在js文件下,

主模塊的寫法

如果不依賴任何模塊,就可以直接寫JavaScript代碼,但是這就沒必要用require.js了,
要加載模塊,就要使用require函數(shù)

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

一般的加載方式就是這樣,首先接受一個模塊數(shù)組參數(shù),然后有一個回調(diào)函數(shù),數(shù)組作為函數(shù)的參數(shù)傳入,模塊數(shù)組中的模塊都是異步加載的

模塊的加載

在下面的例子中

require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
// some code here
});

加載了三個模塊,但是并沒有提這些模塊的具體地址、也沒有對回調(diào)函數(shù)的傳參使用別名,這里還需要在require.config方法中進(jìn)行設(shè)置

require.config({
baseUrl:"js/lib",//相對main.js的目錄位置
path:{
"jquery": "jquery.min",//在這個目錄下的文件名,可忽略js后綴
"underscore": "underscore.min",
"backbone": "backbone.min"
}
});

還可以直接寫cdn地址

require.config({
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
}
});

AMD模塊的寫法

require.js要求加載的模塊按照AMD的規(guī)范去寫
假設(shè)有一個math模塊,就要這樣去寫

\\mah.js
define( function()
{
var add=function(x,y)
{
return x+y;
};
return{add:add}
});

加載

//main.js
require(["math"],function(math){
alert(math.add(1,2));
});

如果這個模塊還依賴其他模塊,那么define()函數(shù)的第一個參數(shù),必須是一個數(shù)組,指明該模塊的依賴性。

 define(['myLib'], function(myLib){
   function foo(){
    myLib.doSomething();
    }
    return {
      foo : foo
    };
  });

加載非AMD規(guī)范模塊

實(shí)際上有很多模塊并不是按照AMD規(guī)范去寫的,require.js加載這些模塊需要在require.config中的shim屬性中添加相應(yīng)的依賴關(guān)系和導(dǎo)出標(biāo)記

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

require.js還提供一系列[插件],實(shí)現(xiàn)一些特定的功能。
domready插件,可以讓回調(diào)函數(shù)在頁面DOM結(jié)構(gòu)加載完成后再運(yùn)行。

  require(['domready!'], function (doc){
    // called once the DOM is ready
  });

text和image插件,則是允許require.js加載文本和圖片文件。

  define([
    'text!review.txt',
    'image!cat.jpg'
    ],    function(review,cat){
      console.log(review);
      document.body.appendChild(cat);
    }
  );

類似的插件還有json和mdown,用于加載json文件和markdown文件。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容