模塊化方式
什么是模塊化
所謂的模塊化開發(fā)就是封裝細(xì)節(jié),提供使用接口,彼此之間互不影響,每個(gè)模塊都是實(shí)現(xiàn)某一特定的功能。模塊化開發(fā)的基礎(chǔ)就是函數(shù)
-
函數(shù)封裝
- "污染"了全局變量,無法保證不與其他模塊發(fā)生變量名沖突,而且模塊成員之間看不出直接關(guān)系。
-
對(duì)象方式
var module1 = { _count : 0, m1 : function (){ //... }, m2 : function (){ //... } } // 這樣的寫法會(huì)暴露所有模塊成員,內(nèi)部狀態(tài)可以被外部改寫。比如,外部代碼可以直接改變內(nèi)部計(jì)數(shù)器的值。module1._count = 1; -
IIFE
var module1 = (function(){ var _count = 0; var m1 = function(){ //... }; var m2 = function(){ //... }; return { m1 : m1, m2 : m2 }; })(); -
放大模式
- 如果一個(gè)模塊很大,必須分成幾個(gè)部分,或者一個(gè)模塊需要繼承另一個(gè)模塊,這時(shí)就有必要采用"放大模式"(augmentation)。在原有的基礎(chǔ)上擴(kuò)展更多的方法
var module1 = (function (mod){ mod.m3 = function () { //... }; return mod; })(module1); // 上面的代碼為module1模塊添加了一個(gè)新方法m3(),然后返回新的module1模塊,方便方法連續(xù)調(diào)用。如何防止module1為null或underfined的情況了? -
寬放大模式
- 在瀏覽器環(huán)境中,模塊的各個(gè)部分通常都是從網(wǎng)上獲取的,有時(shí)無法知道哪個(gè)部分會(huì)先加載。如果采用上面的寫法,第一個(gè)執(zhí)行的部分有可能加載一個(gè)不存在空對(duì)象,這時(shí)就要采用"寬放大模式"。
var module1 = (function (mod){ return mod; })(window.module1 || {}); // 確保對(duì)象不為空 // 與"放大模式"相比,"寬放大模式"就是"立即執(zhí)行函數(shù)"的參數(shù)可以是空對(duì)象,解決了非空問題。 -
輸入全局變量
- 獨(dú)立性是模塊的重要特點(diǎn),模塊內(nèi)部最好不與程序的其他部分直接交互。為了在模塊內(nèi)部調(diào)用全局變量,必須顯式地將其他變量輸入模塊。
var module1 = (function ($, YAHOO) { //... })(jQuery, YAHOO);
COMMONJS 服務(wù)器端同步加載
- 再來說說 module.exports 和 exports,用法其實(shí)是相似的,但是不能對(duì) exports直接賦值,不會(huì)有任何效果。
- 對(duì)于 CommonJS 和 ES6 中的模塊化的兩者區(qū)別是:
- 前者支持動(dòng)態(tài)導(dǎo)入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案
- 前者是同步導(dǎo)入,因?yàn)橛糜诜?wù)端,文件都在本地,同步導(dǎo)入即使卡住主線程影響也不大。而后者是異步導(dǎo)入,因?yàn)橛糜跒g覽器,需要下載文件,如果也采用導(dǎo)入會(huì)對(duì)渲染有很大影響
- 前者在導(dǎo)出時(shí)都是值拷貝,就算導(dǎo)出的值變了,導(dǎo)入的值也不會(huì)改變,所以如果想更新值,必須重新導(dǎo)入一次。但是后者采用實(shí)時(shí)綁定的方式,導(dǎo)入導(dǎo)出的值都指向同一個(gè)內(nèi)存地址,所以導(dǎo)入值會(huì)跟隨導(dǎo)出值變化
- 后者會(huì)編譯成 require/exports 來執(zhí)行的
AMD (Asynchronous Module Definition)
"異步模塊定義"。它采用異步方式加載模塊,模塊的加載不影響它后面語句的運(yùn)行。所有依賴這個(gè)模塊的語句,都定義在一個(gè)回調(diào)函數(shù)中,等到加載完成之后,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。
require([module], callback);
requirejs的使用
-
為什么要使用requirejs
加載的時(shí)候,瀏覽器會(huì)停止網(wǎng)頁渲染,加載文件越多,網(wǎng)頁失去響應(yīng)的時(shí)間就會(huì)越長(zhǎng);
由于js文件之間存在依賴關(guān)系,因此必須嚴(yán)格保證加載順序(比如上例的1.js要在2.js的前面)
依賴性最大的模塊一定要放到最后加載,當(dāng)依賴關(guān)系很復(fù)雜的時(shí)候,代碼的編寫和維護(hù)都會(huì)變得困難。
-
requirejs 特性
- 實(shí)現(xiàn)js文件的異步加載,避免網(wǎng)頁失去響應(yīng);
- 管理模塊之間的依賴性,便于代碼的編寫和維護(hù)。
-
requireJs的加載
<script src="js/require.js" data-main="js/main"></script> 1. data-main屬性的作用是,指定網(wǎng)頁程序的主模塊。 2. 在上例中,就是js目錄下面的main.js,這個(gè)文件會(huì)第一個(gè)被require.js加載。 3. 由于require.js默認(rèn)的文件后綴名是js,所以可以把main.js簡(jiǎn)寫成main。 -
主模塊的寫法
主模塊",意思是整個(gè)網(wǎng)頁的入口代碼。它有點(diǎn)像C語言的main()函數(shù),所有代碼都從這兒開始運(yùn)行。下面就來看,怎么寫main.js。
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ // some code here // require.js會(huì)先加載jQuery、underscore和backbone,然后再運(yùn)行回調(diào)函數(shù)。主模塊的代碼就寫在回調(diào)函數(shù)中。 }); /* require()函數(shù)接受兩個(gè)參數(shù)。 第一個(gè)參數(shù)是一個(gè)數(shù)組,表示所依賴的模塊,上例就是['moduleA', 'moduleB', 'moduleC'],即主模塊依賴這三個(gè)模塊; 第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),當(dāng)前面指定的模塊都加載成功后,它將被調(diào)用。加載的模塊會(huì)以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊。 */