前言:對於JS的模塊化編程,一直都處於邊學邊用的狀態,藉着這次重構代碼的機會,對「JS模塊化編程」作一個系統的完整的學習和整理。(隨時更新)javascript
參考文章:http://www.ruanyifeng.com/blo...html
什麼是模塊化編程?爲何須要模塊化編程?
當一個項目愈來愈大,那麼它包含的JS也會愈來愈多。過多的JS文件會下降代碼的可讀性,同時增長後續的開發和維護成本。容易出現一下情景:
「大神,爲何這個js在執行的時候會報錯?我命名包含進來了呀?」
「我看看...(5分鐘後),汗你這有問題。B.JS依賴於A.JS,因此引入時候要放在A.JS的後面,否則會報錯。」
爲了下降以上現象,引入模塊化編程思想,相似強類型語言的「類」、「模塊」。一個模塊(JS文件)完成一類功能,須要某功能時,引入其對應的模塊(JS文件)便可。java
如何進行模塊化編程?
模塊化是一個思想,當把「同一類」功能的方法(或函數)放到一塊兒,造成一個「類」,咱們就能夠把它們當成一個模塊:編程
function m1(){ //計算手續費... //... } function m2(){ //計算收益... //... }
這樣,m1和m2就算是組成一個模塊了。可是,這樣的寫法「污染」了全局變量。好比,此時新來了一個同事C,他不知道m一、m2已經被前輩「佔」用了,而後本身寫了一個「模塊」,也包含了名爲m一、m2的方法。同事C在本身代碼裏引用以上模塊時,就會出現同名方法。爲了不以上問題,又對模塊化進行「升級」。服務器
模塊化編程造成
將模塊寫成對象,這樣即便重名了,由於方法屬於不一樣對象,因此不會形成衝突:異步
var module1 = new Object({ _count : 0, m1 : function (){ //... }, m2 : function (){ //... } });
這樣一來,同事C即便本身寫了一個模塊(對象),模塊(對象)裏包含同名方法也不須要擔憂衝突了模塊化
模塊化編程演變
有一天,技術大佬找到同事C,說他寫的模塊有問題,同事D在調用的時候發現BUG。同事C一臉懵逼的跑回座位上看着本身寫的模塊,內心泛着低估「本身命名都用了那麼久了,沒啥問題」。查看了一下同事D的代碼後,發現同事D不當心將他代碼裏邊的變量_count變成了空字符串:函數
module1._count=""
因此在使用其餘方法的時候才報錯,於找到同事D痛批了一頓...
後來回到座位上,同事C思考了,雖然只是不當心,可是萬一其餘人也不當心那可不行。因而,同事C想到了java裏邊的private變量,若是讓全部模塊都只暴露出方法,而不暴露屬性,這樣就能夠避免了這個問題的再次發生。學習
模塊化編程的雛形
經過「當即執行函數」,單獨將須要暴露出來的方法返回:ui
var module1 = (function(){ var _count = 0; var m1 = function(){ //... }; var m2 = function(){ //... }; return { m1 : m1, m2 : m2 }; })();
模塊化編程的改造
同事C在開發的時候,引入了一個好久之前寫了模塊,他發現一個問題:若是要在原先寫好的模塊上新增功能,那麼就必需要改這個模塊,可是這麼一來就有可能影響到其餘使用這個模塊的項目。若是再準備一個新的模塊,而後把原來寫好的模塊複製出來,而後在這模塊上新增功能,這樣就出現重複代碼了。後來通過細心的斟酌,同事C改裝一下本身的模塊,增長模塊的擴展性:放大模式。
var module1 = (function (mod){ mod.m3 = function () { //... }; return mod; })(module1);
模塊化的規範:AMD(異步模塊定義,Asynchronous Module Definition)
AMD規定,採用require()方法進行加載模塊。require()包含兩個參數:模塊、回調函數。
require([module], callback);
第一個參數:模塊,表示當前JS文件(也能夠是模塊)包含哪些模塊;
第二個參數:回調函數,當所需的模塊(第一個參數)被從服務器中下載並加載完成後進行調用。
AMD的實現待更新...