在JavaScript模塊到底是什么,能用代碼具體展現一下嗎?
其實上一篇已經寫了一段事件模塊代碼
event = function() { // do more return { bind: function() {}, unbind: function() {}, trigger: function() {} }; }();
這能代表“模塊”嗎?這就是一個JS對象啊,以為有多么深奧。
是的,JavaScript中模塊多數時候被實現為一個對象。這么看來,多數時候我們都寫過“模塊”(但沒有在整個項目中應用模塊化思想)。或許每個人寫模塊的方式(風格)還不同。比如上面的事件模塊是一個匿名函數執行,匿名函數中封裝了很多代碼,最后通過return返回給event變量,這個event就是事件模塊的接口。
又如jQuery,它也是一個匿名函數執行,但它並不返回接口對象。而是將自己暴露給window對象。
(function(window){ // .. // exports window.jQuery = window.$ = jQuery; })(window);
再如SeaJS,它一開始就將接口公開了
/** * Base namespace for the framework. */ this.seajs = { _seajs: this.seajs };
后續是很多的匿名函數執行給變量seajs添加很多工具方法。注意,這里的this在瀏覽器環境指window對象,如果是定位在瀏覽器中,這個this也可以去掉。就象Ext。
Ext = { /** * The version of the framework * @type String */ version : '3.1.0' };
呃,我們已經看到了四種方式寫模塊(把jQuery,SeaJS,Ext看成模塊,呃很大的模塊)。
哪一種更好呢? 哪一種更適合在瀏覽器端呢?純從代碼風格上說,是蘿卜白菜各有所愛。只要我們運用了“模塊化”的思想來開發就行了。
但如果有一種統一的語法格式來寫模塊豈不是更好,就不會出現各用各的風格來寫模塊而使代碼亂糟糟。
這就是目前的現狀,開發者強烈需要一種統一的風格來寫模塊(最好是語言內置了)。這時一些組織出現了,最具代表的如CommonJS,AMD。此外ECMAScript也開始着手模塊的標准化寫法。
無論它們提供什么樣的寫法,我們需要的僅僅是
- 將一些零散代碼封裝成一個有用的單元(encapsulate)
- 導出模塊的接口API(exports)
- 方便友好引用其它模塊(dependency)
服務器端的JSer是幸運的,它有Node.js,Node.js遵循了一個稱為CommonJS的規范。CommonJS其中就有對寫模塊的標准化。當然模塊化只是其中的一部分而已。具體來說Node.js實現了
- Modules/1.0
- Promises/B (http://github.com/kriskowal/q)
- Promises/D (https://github.com/kriskowal/q)
- Unit Testing/1.0
exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; };
increment.js
var add = require('math').add; exports.increment = function(val) { return add(val, 1); };
main.js,該文件為入口文件
var inc = require('increment').increment; var a = 1; inc(a); // 2
這就寫了一個math、increment、main模塊。math提供了add方法來實現數字相加。increment模塊依賴於math模塊,它提供increment方法實現相加。main獲取到increment方法,執行相加操作。
以上代碼示例可以看到
- node要求一個js文件對應一個模塊。可以把該文件中的代碼想象成是包在一個匿名函數中,所有代碼都在匿名函數中,其它模塊不可訪問除exports外的私有變量
- 使用exports導出API
- 使用require加載其它模塊
- 標示符require,為一個函數,它僅有一個參數為字符串,該字符串須遵守Module Identifiers的6點規定
- require方法返回指定的模塊API
- 如果存在依賴的其它模塊,那么依次加載
- require不能返回,則拋異常
- 僅能使用標示符exports導出API
Modules/1.1較1.0僅增加了標示符module,require函數增加了main和paths屬性。而仔細比對1.1與1.1.1后發現除了格式調整了下幾乎沒有變化。
相關: