一,JS模塊化演變過程 1.普通函數封裝 最初的這種普通函數封裝的缺點很明顯:污染了全局變數,無法避免的會與其他模塊發生變數名衝突,而且自身模塊成員之間沒有任何聯繫,,說白了就是沒有做到“高內聚,低耦合”原則 2.對象 技術一直在進步,這種做法的避免了變數污染,只要保證模塊名唯一即可,自身模塊內的成 ...
一,JS模塊化演變過程
1.普通函數封裝
1 function fn1(){ 2 3 } 4 5 function fn2(){ 6 7 }
最初的這種普通函數封裝的缺點很明顯:污染了全局變數,無法避免的會與其他模塊發生變數名衝突,而且自身模塊成員之間沒有任何聯繫,,說白了就是沒有做到“高內聚,低耦合”原則
2.對象
1 var myModule = { 2 var1: 1, 3 var2: 2, 4 fn1: function(){ 5 6 }, 7 fn2: function(){ 8 9 } 10 }
技術一直在進步,這種做法的避免了變數污染,只要保證模塊名唯一即可,自身模塊內的成員也有了聯繫;
但是新的問題出現了,看似不錯的解決方案,也有缺陷,外部可以隨意修改內部成員;
如:myModel.val = 100; 說白了就是產生了安全問題
3.立即執行函數
1 var myModule = (function(){ 2 var var1 = 1; 3 var var2 = 2; 4 function fn1(){ 5 6 } 7 function fn2(){ 8 9 } 10 return { 11 fn1: fn1, fn2: fn2 12 }; 13 })();
這種做法就是我們JS模塊化的基礎,技術永無止境,隨著JS模塊化技術提高,產生了不同流派,分支;其中主要有兩種:CommonJS和AMD
二,CommonJS
1.定義模塊:
根據CommonJS規範,一個單獨的文件為一個模塊,每個模塊是一個單獨的作用域,即在自身模塊內部定義的變數,其他模塊無法讀取,除非是定義為global對象的屬性
2.模塊輸出:
每個模塊只有一個出口,即module.exports對象,我們需要把模塊希望輸出的內容放入該對象
3.載入模塊:
載入模塊使用require方法,該方法讀取一個文件並執行,返迴文件內部的module.exports對象
1 //模塊定義 2 myModel.js 3 var name = 'Byron'; 4 function printName(){ 5 console.log(name); 6 } 7 function printFullName(firstName){ 8 console.log(firstName + name); 9 } 10 module.exports = { 11 printName: printName, 12 printFullName: printFullName 13 } 14 //載入模塊 15 var nameModule = require('./myModel.js'); 16 nameModule.printName();
不同的實現對require時的路徑有不同要求,一般情況可以省略js拓展名,可以使用相對路徑,也可以使用絕對路徑,甚至可以省略路徑直接使用模塊名(前提是該模塊是系統內置模塊)
問題:
仔細看上面的代碼,會發現require是同步的。模塊系統需要同步讀取模塊文件內容,並編譯執行以得到模塊介面。
這在伺服器端實現很簡單,也很自然,然而, 想在瀏覽器端實現問題卻很多。
瀏覽器端,載入JavaScript最佳、最容易的方式是在document中插入script 標簽。但腳本標簽天生非同步,傳統CommonJS模塊在瀏覽器環境中無法正常載入。
解決思路之一是,開發一個伺服器端組件,對模塊代碼作靜態分析,將模塊與它的依賴列表一起返回給瀏覽器端。 這很好使,但需要伺服器安裝額外的組件,並因此要調整一系列底層架構。
另一種解決思路是,用一套標準模板來封裝模塊定義,但是對於模塊應該怎麼定義和怎麼載入,又產生的分
三,AMD
AMD 即Asynchronous Module Definition,中文名是非同步模塊定義的意思。它是一個在瀏覽器端模塊化開發的規範。
由於不是JavaScript原生支持,使用AMD規範進行頁面開發需要用到對應的庫函數,也就是大名鼎鼎RequireJS,實際上AMD 是 RequireJS 在推廣過程中對模塊定義的規範化的產出。
requireJS主要解決兩個問題
1.多個js文件可能有依賴關係,被依賴的文件需要早於依賴它的文件載入到瀏覽器2.js載入的時候瀏覽器會停止頁面渲染,載入文件越多,頁面失去響應時間越長
語法
requireJS定義了一個函數 define,它是全局變數,用來定義模塊。
define(id?, dependencies?, factory);
id:可選參數,用來定義模塊的標識,如果沒有提供該參數,腳本文件名(去掉拓展名);
dependencies:是一個當前模塊依賴的模塊名稱數組
factory:工廠方法,模塊初始化要執行的函數或對象。如果為函數,它應該只被執行一次。如果是對象,此對象應該為模塊的輸出值;
1 // 定義模塊 2 myModule.js 3 define(['dependency'], function(){ 4 var name = 'xlw'; 5 function printName(){ 6 console.log(name); 7 } 8 return { 9 printName: printName 10 }; 11 }); 12 // 載入模塊 13 require(['myModule'], function (my){ 14 my.printName(); 15 });
在頁面上使用require函數載入模塊
1 require([dependencies], function(){ 2 3 });
require()函數接受兩個參數
第一個參數是一個數組,表示所依賴的模塊
第二個參數是一個回調函數,當前面指定的模塊都載入成功後,它將被調用。載入的模塊會以參數形式傳入該函數,從而在回調函數內部就可以使用這些模塊
require()函數在載入依賴的函數的時候是非同步載入的,這樣瀏覽器不會失去響應,它指定的回調函數,只有前面的模塊都載入成功後,才會運行,解決了依賴性的問題。
敬請留言指正補充
(完~~)