1. 程式人生 > >(轉)Node.js module.exports與exports

(轉)Node.js module.exports與exports

var 的區別 開發者 () 使用 不同 不用 構造 filename

本文轉自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();

總結下,有兩點:

  1. 對於要導出的屬性,可以簡單直接掛到exports對象上
  2. 對於類,為了直接使導出的內容作為類的構造器可以讓調用者使用new操作符創建實例對象,應該把構造函數掛到module.exports對象上,不要和導出屬性值混在一起
    最後,不用再糾結module.exports與exorts什麽時候該用哪個了吧~

(轉)Node.js module.exports與exports