1、模塊化開發(fā)
1.什么是模塊化開發(fā)?
簡單的說模塊就是實現(xiàn)特定功能的一組方法。
模塊化開發(fā)其實就是讓JavaScript文件可以互相引用,每個文檔代表一個模塊,提高代碼的使用頻率。
模塊化是一種將系統(tǒng)分離成獨立功能部分的方法,可將系統(tǒng)分割成獨立的功能部分,嚴格定義模塊接口、模塊間具有透明性。
2.模塊化開發(fā)的優(yōu)缺點有哪些?
優(yōu)點:
1.便于多人協(xié)作開發(fā),每個部分開發(fā)不會干擾其它地方
2.便于調(diào)試修改,因為模塊獨立,發(fā)現(xiàn)問題比較容易,修改一處,也不影響別處,利于前端性能優(yōu)化
3.利于代碼復用,小塊的代碼可以更方便拿到別的項目中不加或者稍加修改使用,提高可維護性
4.便于功能的擴充,因為軟件各個部分是獨立的,不需要理解整個軟件就可以添加功能,特別適合二次開發(fā)。
5.解決了部分惱人的命名沖突以及煩瑣的文件依賴
缺點:
1.系統(tǒng)分層,調(diào)用鏈會很長
2.模塊間通信,模塊間發(fā)送消息會很耗性能
模塊化的意義在于最大化的設(shè)計重用,以最少的模塊、零部件,更快速的滿足更多的個性化需求。
3.常見的模塊化的寫法有哪些
- 原始寫法(封裝函數(shù))
function m1(){ //... } function m2(){ //... }
這種做法的缺點很明顯:"污染"了全局變量,無法保證不與其他模塊發(fā)生變量名沖突,而且模塊成員之間看不出直接關(guān)系。
-
對象寫法
為了解決原始封裝函數(shù)的缺點,可以把模塊寫成一個對象,所有的模塊成員都放到這個對象里面。var module1 = new Object({ _count : 0, m1 : function (){ //... }, m2 : function (){ //... } });方法都封裝在module1對象里。使用的時候,就是調(diào)用這個對象的屬性。例如:
module1.m1();但是,這樣的寫法會暴露所有模塊成員,內(nèi)部狀態(tài)可以被外部改寫。比如module1._count = 5;,外部代碼可以直接改變內(nèi)部計數(shù)器的值。 -
立即執(zhí)行函數(shù)寫法
立即執(zhí)行函數(shù)可以達到不暴露私有成員的目的。var module1 = (function(){ var _count = 0; var m1 = function(){ //... }; var m2 = function(){ //... }; return { m1 : m1, m2 : m2 }; })();外部代碼無法讀取內(nèi)部的_count變量。
2、模塊化規(guī)范
1.模塊的規(guī)范有哪些?
模塊的規(guī)范有CommonJS(nodeJS),AMD(requireJS),CMD(sea.js)
原生JavaScript中并不支持模塊化開發(fā),所以出現(xiàn)了一些規(guī)范,就是所說的AMD和CMD,這兩種方式適合使用桌面端,可以進行異步加載,而在NodeJS中使用CommonJS是同步的,所以CommonJS并不適合桌面端。
2.CommonJS
NodeJS實現(xiàn)了JavaScript語言編寫后臺,其中使用CommonJS規(guī)范實現(xiàn)了模塊化開發(fā)
CommonJS定義的模塊分為:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
require()用來引入外部模塊;exports對象用于導出當前模塊的方法或變量,唯一的導出口;module對象就代表模塊本身。
3.AMD
AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"。它采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到加載完成之后,這個回調(diào)函數(shù)才會運行。
AMD也采用require()語句加載模塊,但是不同于CommonJS,它要求兩個參數(shù):
require([module], callback);
第一個參數(shù)[module],是一個數(shù)組,里面的成員就是要加載的模塊;第二個參數(shù)callback,則是加載成功之后的回調(diào)函數(shù)。
異步加載,瀏覽器不會假死,所以AMD比較適合瀏覽器環(huán)境。
4.CMD
玉伯寫了seajs,就是遵循他提出的CMD規(guī)范,與AMD蠻相近的,不過用起來感覺更加方便些,最重要的是中文版。
define(function(require,exports,module){...});
3、requireJs
1.require.js的誕生,就是為了解決這兩個問題:
1.實現(xiàn)js文件的異步加載,避免網(wǎng)頁失去響應(yīng);
2.管理模塊之間的依賴性,便于代碼的編寫和維護。
2.requireJS的使用步驟
1.在要使用的主頁面引入requirejs文件
<script src="js/require.js" defer async="true" ></script>
defer async="true"可以解決可能造成網(wǎng)頁失去響應(yīng)的問題。
async屬性表明這個文件需要異步加載,避免網(wǎng)頁失去響應(yīng)。IE不支持這個屬性,只支持defer,所以把defer也寫上。
2.加載我們自己的代碼,假定我們自己的代碼文件是main.js,也放在js目錄下面。
<script src="js/require.js" data-main="js/main"></script>
data-main屬性的作用是,指定網(wǎng)頁程序的主模塊。
3.編寫模塊的依賴
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
require()函數(shù)接受兩個參數(shù)。第一個參數(shù)是一個數(shù)組,表示所依賴的模塊,第二個參數(shù)是一個回調(diào)函數(shù),當前面指定的模塊都加載成功后,它將被調(diào)用。加載的模塊會以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊。
4.模塊的加載
使用require.config()方法,我們可以對模塊的加載行為進行自定義。require.config()就寫在主模塊(main.js)的頭部。參數(shù)就是一個對象,這個對象的paths屬性指定各個模塊的加載路徑。
require.config({
//規(guī)范的模塊
paths: {
"underscore": "lib/underscore.min",
"backbone": "lib/backbone.min",
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
},
//非規(guī)范的模塊
shim: {
'underscore':{
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
}
});
5.AMD模塊的定義
require.js加載的模塊,采用AMD規(guī)范。也就是說,模塊必須按照AMD的規(guī)定來寫。
具體來說,就是模塊必須采用特定的define()函數(shù)來定義。如果一個模塊不依賴其他模塊,那么可以直接定義在define()函數(shù)之中。
//定義模塊
// math.js
define(function (){
var add = function (x,y){
return x+y;
};
return {
add: add
};
});
//加載模塊
require(['math'], function (math){
alert(math.add(1,1));
});