第一步javascript
只要把不一樣的函數(以及記錄狀態的變量)簡單地放在一塊兒,就算是一個模塊。Global全局污染,容易命名衝突html
function foo(){ //... } function bar(){ //... }
第二步 Namespacejava
雖然減小了Global變量的數量,可是這樣的寫法會暴露全部模塊成員,內部狀態能夠被外部改寫。jquery
var name = { foo: function(){ }, bar: function(){ } } // 使用 name.foo();
第三步 IIFE模式webpack
閉包模式,經過當即執行函數寫法,能夠達到不暴露私有變量的目的。且外部沒法訪問內部的值。es6
var module = (function(){ var _private = 'sss'; var foo = function(){ } return { foo: foo } })(); module.foo(); module._private; // undefined
引入依賴web
// 改進一些 var Module = (function($){ var _$body = $("body"); // we can use jQuery now! var foo = function(){ console.log(_$body); // 特權方法 } // Revelation Pattern return { foo: foo } })(jQuery) Module.foo();
// 依賴其餘 var module1 = (function (mod){ mod.m3 = function () { //... }; return mod; })(module1);
// 其餘擴展 var MODULE = (function (my) { // add capabilities... return my; }(MODULE || {})); // 能夠傳入空對象
var MODULE = (function (my) { var old_moduleMethod = my.moduleMethod; my.moduleMethod = function () { // 方法重載 // 可經過 old_moduleMethod 調用之前的方法... }; return my; }(MODULE)); // 有時咱們要求在擴展時調用之前已被定義的方法,這也有可能被用於覆蓋已有的方法。這時,對模塊的定義順序是有要求的。
Script Loader
經過script標籤引入一堆的依賴,按序執行。一樣難以維護,依賴過多。編程
body script(src="zepto.js") script(src="jhash.js") script(src="fastClick.js") script(src="iScroll.js") script(src="underscore.js") script(src="handlebar.js") script(src="datacenter.js") script(src="deferred.js") script(src="util/wxbridge.js") script(src="util/login.js") script(src="util/base.js") script(src="util/city.js") script(src="util/date.js") script(src="util/cookie.js") script(src="app.js")
這樣的寫法有很大的缺點。首先,加載的時候,瀏覽器會中止網頁渲染,加載文件越多,網頁失去響應的時間就會越長;其次,因爲js文件之間存在依賴關係,所以必須嚴格保證加載順序(好比上例的1.js要在2.js的前面),依賴性最大的模塊必定要放到最後加載,當依賴關係很複雜的時候,代碼的編寫和維護都會變得困難。
CommonJS 征服世界的第一步是跳出瀏覽器。segmentfault
CommonJS規範的提出,主要時爲了彌補js沒有標準的缺陷,使得經過CommonJS Api編寫的應用能夠在不一樣的宿主環境中執行。瀏覽器
由於老實說,在瀏覽器環境下,沒有模塊也不是特別大的問題,畢竟網頁程序的複雜性有限;可是在服務器端,必定要有模塊,與操做系統和其餘應用程序互動,不然根本無法編程。所以Node就在Commonjs的基礎上應運而生了。
【NodeJS
是CommonJS
規範的實現,webpack
也是以CommonJS
的形式來書寫】
AMD/CMD 瀏覽器環境模塊化方案
AMD(Asynchronous Module Definition:異步模塊定義)
是 RequireJS
在推廣過程當中對模塊定義的規範化產出。
CMD(Common Module Definition:公共模塊定義)
是 SeaJS
在推廣過程當中對模塊定義的規範化產出。
有了服務器端模塊之後,很天然地,你們就想要客戶端模塊。並且最好二者可以兼容,一個模塊不用修改,在服務器和瀏覽器均可以運行。
可是,因爲一個重大的侷限,使得CommonJS規範不適用於瀏覽器環境。下面的代碼,若是在瀏覽器中運行,會有一個很大的問題,你能看出來嗎?
var math = require('math'); math.add(2, 3);
第二行math.add(2, 3),在第一行require('math')以後運行,所以必須等math.js加載完成。也就是說,若是加載時間很長,整個應用就會停在那裏等。
這對服務器端不是一個問題,由於全部的模塊都存放在本地硬盤,能夠同步加載完成,等待時間就是硬盤的讀取時間。可是,對於瀏覽器,這倒是一個大問題,由於模塊都放在服務器端,等待時間取決於網速的快慢,可能要等很長時間,瀏覽器處於"假死"狀態。
所以,在瀏覽器就須要"異步加載"(asynchronous)。這就是AMD
規範誕生的背景。
目前,主要有兩個Javascript庫實現了AMD規範:require.js
和curl.js
。
Require.JS
Require.JS 的基本功能"模塊化加載"。
實例1
// math1.js /* 語法結構: 1. define({函數方法}) */ // 一個沒有依賴性的模塊能夠直接定義對象 define({ name: '測試', add: function(num1, num2) { return num1+num2; } })
// test1.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="./lib/require.js" charset="utf-8"></script> <script type="text/javascript"> require(['math1'], function(math) { console.log(math.name); console.log(math.add(1,3)); }) </script> </body> </html>
實例二
// math2.js /* 語法結構: 2. define([引入其餘模塊地址],回調函數(引入模塊別名)); 別名能夠在函數裏面去調用其餘模塊提供的方法 */ // 一個返回對象的匿名模塊 define(['math1'], function(math) { var sub = function(num1,num2) { return num1 - num2; } return { add: math.add, sub: sub } })
// test2.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="./lib/require.js" charset="utf-8"></script> <script type="text/javascript"> require(['math2'], function(math) { console.log(math.sub(4,2)); }) </script> </body> </html>
實例三
// math3.js // 定義一個命名模塊 define('mymath', ['math2'], function(math) { var multiplication = function(num1, num2) { return num1 * num2; } return { add: math.add, sub: math.sub, mult: multiplication } })
// test3.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="./lib/require.js" charset="utf-8"></script> <script type="text/javascript"> //須要配置一下引入的模塊的地址 require.config({ paths:{ 'mymath': 'math3' } }); require(['mymath'], function(math){ console.log(math.mult(3,5)); }) </script> </body> </html>
下圖有一些注意事項,可是截圖不是本實例的截圖
實例四
// math4.js // 一個使用了簡單CommonJS轉換的模塊定義 define(function(require,exports,module){ // 引入其餘模塊 var math = require('js/1_math'); console.log(math); // 導出(暴露方法:2種方式) // 第一種 // exports.a = math.add; // 第二種 module.exports = { a : math.add } });
// test4.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> </body> <script type="text/javascript" src="js/require.js"></script> <script type="text/javascript"> require(['js/4_math'],function(mytool){ console.log(mytool.a(11,22));//33 }); </script> </html>
一個小demo
// index.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> <h1>My Sample Project</h1> <script src="./script/require.js" data-main="./script/main" charset="utf-8"></script> </body> </html>
// main.js require.config({ baseUrl: 'script', paths: { math: './lib/math1', utils: './utils/utils', jquery: './lib/jquery.min' } }); require(['math','utils','jquery'], function(math, utils, $) { $(function(){ console.log(math.add(1,2)); console.log(utils.utils.sub(4,2)); alert('在加載完math、utils、jquery以後,我執行了'); }) })
//math.js define({ add:function(num1, num2) { return num1+num2; } });
// utils.js define(function(require, exports, module) { var utils = { sub:function(num1, num2) { return num1-num2; } }; module.exports = { utils: utils } })
SeaJS 是一個適用於 Web 瀏覽器端的模塊加載器。這裏就先不寫了~
你們能夠參考文檔學習
面向將來的ES6模塊標準
2015年6月,ECMAScript2015也就是ES6發佈了,JavaScript終於在語言標準的層面上,實現了模塊功能,使得在編譯時就能肯定模塊的依賴關係,以及其輸入和輸出的變量,不像 CommonJS、AMD之類的須要在運行時才能肯定(例如FIS這樣的工具只能預處理依賴關係,本質上仍是運行時解析),成爲瀏覽器和服務器通用的模塊解決方案。
更多關於ES6 Modules的資料,能夠看一下ES6阮一峯
感謝您的支持!!