前言 |
前端開發中,起初只要在script
標籤中嵌入幾十上百行代碼就能實現一些基本的交互效果,後來js獲得重視,應用也普遍起來了,jQuery,Ajax,Node.Js,MVC,MVVM
等的助力也使得前端開發獲得重視,也使得前端項目愈來愈複雜,然而,JavaScript
卻沒有爲組織代碼提供任何明顯幫助,甚至沒有類的概念,更不用說模塊(module)了,因此,進行模塊化開發的重要性就不言而喻了。那麼什麼是模塊呢?前端
一個模塊就是實現特定功能的文件,有了模塊,咱們就能夠更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊。node
因此,今天小編介紹一下js模塊化開發的幾種方法。jquery
1、模塊化開發規範 |
js模塊化的開發並非爲所欲爲的,爲了便於他人的使用和交流,須要遵循必定的規範。目前,通行的js模塊規範主要有兩種:CommonJS
和AMD
。ajax
AMD 即Asynchronous Module Definition
,中文名是「異步模塊定義」的意思。它是一個在瀏覽器端模塊化開發的規範,服務器端的規範是CommonJS;
api
模塊將被異步加載,模塊加載不影響後面語句的運行。全部依賴某些模塊的語句均放置在回調函數中。數組
關於AMD有兩個很是重要的概念,那就是用於模塊定義的define方法和用於處理依賴加載的require方法。瀏覽器
(1)做爲一個規範,只需定義其語法API,而不關心其實現。define函數定義以下:服務器
1 define( 2 [module-name?] /*可選*/, 3 [array-of-dependencies?] /*可選*/, 4 [module-factory-or-object] 5 );
舉個栗子:閉包
define(
"myModule",
["foo", "bar"],
// 模塊定義函數,依賴(foo,bar)做爲參數映射到函數上
function (foo, bar) {
// 建立模塊
var myModule = {
myFun: function () {
console.log("Jeri");
}
}
// 返回定義的模塊
return myModule;
}
);
(2)require()方法,有兩個參數:app
require([module], callback);
其中:
舉個實際栗子:
1 require(['math'], function (math) { 2 math.add(2, 3); 3 });
CommonJS
是服務器端模塊的規範,根據CommonJS
規範,一個單獨的文件就是一個模塊。每個模塊都是一個單獨的做用域,也就是說,在該模塊內部定義的變量,沒法被其餘模塊讀取,除非定義爲global
對象的屬性。輸出模塊變量的最好方法是使用module.exports
對象。
不過,與AMD表現形式不一樣的是,CommonJS模塊並不使用define進行定義。CommonJS模塊由兩部分組成:變量exports和require函數。
(1)exports/require:加載模塊使用require
方法,該方法讀取一個文件並執行,最後返回文件內部的module.exports
對象。
再舉個栗子:建立兩個js文件:
libJS:
1 // 新定義的模塊方法 2 function log(arg) { 3 console.log(arg); 4 } 5 6 // 把方法暴露給其餘模塊 7 exports.log = log;
app.JS:
1 // ./lib是咱們須要的一個依賴 2 var lib = requrie("./lib"); 3 4 // 新定義的模塊方法 5 function foo() { 6 lib.log("jeri"); 7 } 8 9 // 把方法暴露給其餘模塊 10 exports.foo = foo;
(2)module.exports
直接舉栗子:
1 var i = 1; 2 var max = 30; 3 4 module.exports = function () { 5 for (i -= 1; i++ < max; ) { 6 console.log(i); 7 } 8 max *= 1.1; 9 };
2、JS模塊的經常使用寫法 |
在前言中小編也提過,模塊:就是一個模塊就是實現特定功能的文件,有了模塊,咱們就能夠更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊。
除了接下來要講的require.js,還有適合於一些簡單模塊的幾種經常使用寫法。
要知道,模塊就是實現特定功能的一組方法。
只要把不一樣的函數(以及記錄狀態的變量)簡單地放在一塊兒,就算是一個模塊。這也是最簡單的一種寫法。也就是說,每個函數就是一個簡單的模塊。
1 function func1 (){ 2 alert("這是func1"); 3 }; 4 function func2 (){ 5 alert("這是func2"); 6 }
把栗子中的兩個函數func1()和func2()就組成了一個模塊;
不過,這種寫法有着必定的缺點:
若是隻是實現一些簡單的功能還好,若是實現複雜的功能,太多的函數就會出現問題,"污染"了全局變量,沒法保證不與其餘模塊發生變量名衝突,並且模塊成員之間看不出直接關係。
因此,爲了解決上述的問題,把模塊寫成一個對象,全部的模塊成員都放到這個對象裏面不失爲一個好的方式。
再再舉個栗子:
1 var module = { 2 func1 : function(){ 3 alert(1); 4 } 5 6 func2 : function(){ 7 alert(2); 8 } 9 } 10 11 module.func1(); 12 module.func2();
在JavaScript中,並不能能夠直接聲明類,但咱們可使用閉包來封裝私有的屬性和方法,進而模擬類的概念,在JavaScript中實現Module模式;
瘋狂的舉栗子:
1 var myModule = (function () { 2 3 // 私有變量 4 var privateVar = 0; 5 6 // 私有函數 7 var privateFun = function (foo) { 8 console.log(foo); 9 }; 10 11 return { 12 // 私有變量 13 publicVar: "foo", 14 15 // 公有函數 16 publicFun: function (arg) { 17 18 // 修改私有變量 19 privateVar ++; 20 21 // 傳入bar調用私有方法 22 privateFun(arg); 23 } 24 }; 25 }) ()
獨立性是模塊的重要特色,模塊內部最好不與程序的其餘部分直接交互。爲了在模塊內部調用全局變量,必須顯式地將其餘變量輸入模塊。
1 var module1 = (function ($, YAHOO) { 2 //... 3 })(jQuery, YAHOO);
3、require.js |
requir.JS本就是爲了實現js的模塊開發而建立的一個js腳本,其主要有着兩大優勢:
(1)實現js文件的異步加載,避免網頁失去響應;
(2)管理模塊之間的依賴性,便於代碼的編寫和維護。
(1)衆所周知,要導入js文件,爲了不網頁失去響應有兩種方法;
第一種,把<script></script>放在文件的最後。
今天,咱們主要說第二種:
<script src="js/require.js" defer async="true" ></script>
async屬性代表這個文件須要異步加載,避免網頁失去響應。可是,IE不支持這個屬性,只支持defer,因此須要把defer也寫上。
(2)在HTML中導入require.JS文件後,就能夠編寫本身的main.js文件。
首先,導入main.js文件:
<script src="js/require.js" data-main="js/main"></script>
其中:data-main屬性的做用是,指定網頁程序的主模塊。
在上例中,就是js目錄下面的main.js,這個文件會第一個被require.js加載。因爲require.js默認的文件後綴名是js,因此能夠把main.js簡寫成main。
(3)編寫main.js;
1 require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ 2 // some code here 3 });
經過require方法,實現代碼的模塊加載,傳入兩個參數:
①第一個參數是一個數組,表示代碼所依賴的模塊。
②第二個參數是一個回調函數,當前面的模塊加載完成後,就會被調用。
加載的模塊一參數的形式傳入,從而在回調函數內部可使用這些模塊,回調函數就是整個頁面的JS代碼;
再次瘋狂的舉栗子:
1 require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){ 2 // some code here 3 });
在上面的栗子中,咱們可使用require.config()方法,對模塊的加載行爲進行自定義。
(1)require.config()就寫在主模塊(main.js)的頭部。參數就是一個對象,這個對象的paths屬性指定各個模塊的加載路徑。
不要命的舉栗子:
1 require.config({ 2 paths: { 3 "jquery": "jquery.min", 4 "underscore": "underscore.min", 5 "backbone": "backbone.min" 6 } 7 });
(2)上面的代碼給出了三個模塊的文件名,路徑默認與main.js在同一個目錄(js子目錄)。
若是這些模塊在其餘目錄,好比js/lib目錄,則有兩種寫法。
一種是逐一指定路徑。
再次舉栗子:
1 require.config({ 2 paths: { 3 "jquery": "lib/jquery.min", 4 "underscore": "lib/underscore.min", 5 "backbone": "lib/backbone.min" 6 } 7 });
另外一種則是直接改變基目錄(baseUrl)。
再再次舉栗子:
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min"
}
});
(3)若是某個模塊在另外一臺主機上,也能夠直接指定它的網址;
舉栗子:
require.config({
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
}
});
require.js加載的模塊,採用AMD規範。也就是說,模塊必須按照AMD的規定來寫。
具體來講,就是模塊必須採用特定的define()函數來定義。若是一個模塊不依賴其餘模塊,那麼能夠直接定義在define()函數之中。
假定如今有一個math.js文件,它定義了一個math模塊。那麼,math.js就要這樣寫:
1 // math.js 2 3 define(function (){ 4 5 var add = function (x,y){ 6 7 return x+y; 8 9 }; 10 11 return { 12 13 add: add 14 }; 15 16 });
加載方法以下:
1 // main.js 2 3 require(['math'], function (math){ 4 5 alert(math.add(1,1)); 6 7 });
若是這個模塊還依賴其餘模塊,那麼define()函數的第一個參數,必須是一個數組,指明該模塊的依賴性。
1 define(['myLib'], function(myLib){ 2 3 function foo(){ 4 5 myLib.doSomething(); 6 7 } 8 9 return { 10 11 foo : foo 12 13 }; 14 15 });
做者編 |
在平常的工做中,js的模塊法開發是一個不可或缺的一部分。在這裏只是介紹了基於AMD模塊的require.js。還有基於commonJS規範的node.js。小編會在下次和你們一塊兒學習。