(轉)Node.js module.exports與exports
本文轉自Node.js module.exports與exports
作者: chemdemo
折騰Node.js有些日子了,下面將陸陸續續記錄下使用Node.js的一些細節。
熟悉Node.js的童鞋都知道,Node.js作為服務器端的javascript運行環境,它使用npm作為通用的包管理工具,npm遵循CommonJS規範定義了一套用於Node.js模塊的約定,關於npm實現Node.js模塊的更多細節請細讀深入Node.js的模塊機制,這裏簡單講下書寫Node.js代碼時module.exports與exorts的區別。
在瀏覽器端js裏面,為了解決各模塊變量沖突等問題,往往借助於js的閉包把所有模塊相關的代碼都包裝在一個匿名函數裏。而Node.js編寫模塊相當的自由,開發者只需要關註require,exports,module等幾個變量就足夠,而為了保持模塊的可讀性,很推薦把不同功能的代碼塊都寫成獨立模塊,減少各模塊耦合。開發者可以在“全局”環境下任意使用var申明變量(不用寫到閉包裏了),通過exports暴露接口給調用者。
我們經常看到類似export.xxx = yyy
或者module.exports = xx
這樣的代碼,可實際在通過require
函數引入模塊時會出現報錯的情況,這是什麽原因導致的呢?
Node.js在模塊編譯的過程中會對模塊進行包裝,最終會返回類似下面的代碼:
(function (exports, require, module, __filename, __dirname) {
// module code...
});
其中,module就是這個模塊本身,require是對Node.js實現查找模塊的模塊Module._load實例的引用,__filename和__dirname是Node.js在查找該模塊後找到的模塊名稱和模塊絕對路徑,這就是官方API裏頭這兩個全局變量的來歷。
關於module.exports與exorts的區別,了解了下面幾點之後應該就完全明白:
模塊內部大概是這樣:
exports = module.exports = {};
- exports是module.exports的一個引用
- require引用模塊後,返回給調用者的是module.exports而不是exports
- exports.xxx,相當於在導出對象上掛屬性,該屬性對調用模塊直接可見
- exports =相當於給exports對象重新賦值,調用模塊不能訪問exports對象及其屬性
- 如果此模塊是一個類,就應該直接賦值module.exports,這樣調用者就是一個類構造器,可以直接new實例
假如有模塊a.js代碼如下:
exports.str = 'a';
exports.fn = function() {};
對a模塊的調用:
var a = require('./a');
console.log(a.str);
console.log(a.fn());
這樣用是對的,如果改造a如下:
exports.str = 'a';
exports = function fn() {};
在調用a模塊時自然沒用fn屬性了。
再改造下a模塊:
exports.str = 'a';
module.exports = function fn() {};
這時a模塊其實就是fn函數的引用,也就是說可以require(‘./a‘)()這樣使用,而同時不再有str屬性了。
下面直接導出一個類:
module.exports = function A() {};
調用:
var A = require('./a');
var a = new A();
總結下,有兩點:
- 對於要導出的屬性,可以簡單直接掛到exports對象上
- 對於類,為了直接使導出的內容作為類的構造器可以讓調用者使用new操作符創建實例對象,應該把構造函數掛到module.exports對象上,不要和導出屬性值混在一起
最後,不用再糾結module.exports與exorts什麽時候該用哪個了吧~
(轉)Node.js module.exports與exports