Javascript在設計之初並沒有提供一種原生的,語言級別的模塊化方式來組織代碼,比如Java語言通過package和import來管理和使用模塊。ECMAScript 6引入了class和import的概念來支持模塊化,但是瀏覽器全面支持這個標准還需要很長時間。
應用程序的模塊化指的就是通過一些高度解耦的,存放在不同地方的功能模塊構成。近年來隨着Javascript應用的復雜化,大型化,Javascript代碼需要更為有序的組織,在Javascript社區出現了很多種模塊化的實現方式,最主要的兩個規范是CommomJS和AMD,本文會重點闡述這兩個規范。
1. CommonJS
CommonJS是以在瀏覽器之外構建Javascript系統而產生的項目,致力於Javascript模塊的標准化工作。主要特點是同步加載Javascript模塊,運行在服務器端。Node.js 就是CommonJS規范的一個實現。
CommonJS對於模塊的定義非常簡單,分為模塊定義(exports),模塊引用(require),模塊標示三部分。
通過全局變量 exports 返回當前模塊希望提供給其他模塊的對象:
1 // 定義行為 2 function foobar(){ 3 this.foo = function(){ 4 console.log('Hello foo'); 5 } 6 7 this.bar = function(){ 8 console.log('Hello bar'); 9 } 10 } 11 // 把 foobar 暴露給其它模塊 12 exports.foobar = foobar;
通過全局函數 require 來導入其他模塊的輸出:
1 //使用文件與模塊文件在同一目錄 2 var foobar = require('./foobar').foobar, 3 test = new foobar(); 4 test.bar(); // 'Hello bar'
模塊標示其實就是傳遞給require方法的參數,用來指定加載文件路徑,可以沒有后綴名.js,例如上面例子中的 “./foobar”。
2. AMD
AMD(異步模塊定義)是為瀏覽器環境設計的,采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成之后,這個回調函數才會運行。
模塊通過 define 函數定義在閉包中,格式如下:
1 define(id?: String /*可選*/, 2 dependencies?: String /*可選*/, 3 factory: Function|Object /*用來初始化模塊或對象的函數*/);
id 是模塊的名字,它是可選的參數。dependencies 指定了所要依賴的模塊列表,它是一個數組,也是可選的參數,每個依賴的模塊的輸出將作為參數一次傳入 factory 中。factory 是最后一個參數,它包裹了模塊的具體實現,它是一個函數或者對象。如果是函數,那么它的返回值就是模塊的輸出接口或值。
定義一個名為 myModule 的模塊,它依賴 foo, bar 模塊:
1 define('myModule', 2 // 依賴 3 ['foo', 'bar'], 4 // 依賴(foo 和 bar)被映射為函數的參數 5 function ( foo, bar ) { 6 // 返回一個定義了模塊導出接口的值 7 // 在這里創建模塊 8 var myModule = { 9 doSomething:function(){ 10 } 11 } 12 return myModule; 13 });
定義一個獨立模塊,不需要依賴任何其他模塊:
define(function () { return { doSomething: function() {} }; });
通過 require 調用模塊:
1 require(['foo', 'bar'], function ( foo, bar ) { 2 foo.doSomething(); 3 });
在模塊定義內部也可以使用require來加載其他模塊:
1 define(function ( require ) { 2 var isReady = false, foobar; 3 4 require(['foo', 'bar'], function (foo, bar) { 5 isReady = true; 6 foobar = foo() + bar(); 7 }); 8 9 return { 10 isReady: isReady, 11 foobar: foobar 12 }; 13 });
上面的例子中 foo 和 bar沒有加載完成之前,isReady屬性為 false。
目前主要有兩個Javascript庫實現了AMD規范:require.js和curl.js。RequireJS由James Burke創建,他也是AMD規范的創始人。
3. 結語
CommonJS 則采用了服務器優先的策略,使用同步方式加載模塊,而且試圖涵蓋更多更寬泛的東西,例如文件IO,Promise等等。而AMD 采取了一種瀏覽器優先的方式來開發,使用異步方式加載模塊。它支持對象、函數、構造器、字符串、JSON 以及其它許多類型的模塊,運行在瀏覽器本地環境之中。
由於當前版本的Javascript沒有提供原生的模塊化支持,社區的開發者進行了很多模塊化的探索,使得Javascript工程化成為了可能,CommonJS和AMD就是最主要的兩個規范。