隨著互聯網的快速發展,人們不單單只是需要一個網頁了,功能更復雜、交互更豐富的 WebAPP 成為開發者需要面對的日常工作內容。隨之而來的是更加龐大與更加復雜的 JavaScript 代碼,如此而來,僅僅依靠著我們之前面向對象的 JavaScript 進行代碼封裝已很難滿足生產需求,特別是在團隊協作的復雜項目中,JavaScript 模塊化已成為一個迫切的需求。
原始社會的生產
開始的開始 Music ..?.?.?.?...我們都是...咳咳,我們都會使用如下的方式寫代碼,將獨立通用的的功能獨立成一個個函數:
function bar(){
//do something
}
function log(){
//do something
}
這都是最初得美好,那些習以為常的習慣,回憶ing...這是最原始的模塊,需要使用調用就好。但是但是,使用過就會知道這樣會污染全局變量,并且很容易造成 命名沖突,好吧,它屬于最初的美好。
后來,為了解決上面青春期的問題,我們選擇了面向對象寫法,引入 Namespace (命名空間),將代碼進行簡單封裝:
var myModule = {
bar: function(){
//do something
},
log: function(){
//do something
}
}
//調用
myMoudle.bar();
這種方式看似還可以,減少了全局變量,能緩解嚴峻的問題。但是這并不安全,因為實質上是對象,會暴露所有的模塊成員,內部狀態可以被外部讀寫。
沒辦法,出了問題繼續解決,我們采用匿名閉包的寫法(Immediately-Invoked Function Expression,IIFE):
var myModule = (function(){
var _log = "hello world";
var log = function(){
console.log(_log);
};
return {
log: log
}
})();
//引用
myModule.log();//hello world
myModule._log;//undefined
如此,外部就無法讀寫到內部的成員(_log
)。這時候需求又改變了,你的模塊不再是簡單的一個模塊,而是一個功能很大的模塊,需要分成幾個部分,這些部分存在相互之間的 依賴關系。好吧,我們來引入依賴:
var myModule = (function($){
var $log = $('.log');
var log = function(){
console.log($log);
};
return {
log: log
}
})(jQuery);
//引用
myModule.log();
這樣我們在代碼中引入了jQuery,方法間存在依賴關系;
至此,我們用簡陋的工具,和無比勤勞的雙手為子孫們搭建了發展的架子,為后續社會發展出更先進好用的模塊化工具打下了基石,感謝祖輩們的探索!
文明社會的探索
飛速變化的年代里,人們總是不滿足于現狀。有了前人的封裝性還不夠,我們引入 JS 文件時是靠不斷追加 <script src=""></script>
標簽得以實現,每個標簽引入順序是有要求的。
當我們引入的文件增多,除了看起來比較累贅,還會出現比較多的依賴關系,而這種寫法是無法突出這種關系的,我們需要 依賴管理,也讓 后續維護 基本上變得無法進行。
<script src="jquery.js"><script>
<script src="dialog.js"><script>
<script src="tooltip.js"><script>
<script src="toast.js"><script>
<script src="handlebar.js"><script>
......
很多時候可能就是由于之前沒有引入一個依賴的 js 文件而導致后面 js 的功能失效,瀏覽器報錯。大型項目中,一些通用組件往往因此不能輕易地引入到業務代碼中去,生產效率低下。還有一個問題就是 請求過多,不利于性能優化。
時代的進步是注定需要出現偉人的,積累下的訴求注定是需要人來響應的,一些規范橫空出世,諸如 CommonJS規范、AMD規范、CMD規范 等一幫豪杰之輩,懷揣濟世為民之心,度前端開發者于混沌之境。欲知其如何演繹,請看下篇 《前端模塊化之旅(二):CommonJS、AMD和CMD》。