module.exports與exports區別

CommonJS模塊規範

Node應用由模塊組成,採用CommonJS模塊規範。node

根據這個規範,每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。函數

CommonJS規範規定,每一個模塊內部,module變量表明當前模塊。這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口。加載某個模塊,實際上是加載該模塊的module.exports屬性。ui

var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;

上面代碼經過module.exports輸出變量x和函數addX。spa

require方法用於加載模塊。code

var example = require('./example.js');

console.log(example.x); // 5
console.log(example.addX(1)); // 6

exports 與 module.exports

爲了方便,Node爲每一個模塊提供一個exports變量,指向module.exports。這等同在每一個模塊頭部,有一行這樣的命令。對象

var exports = module.exports;

因而咱們能夠直接在 exports 對象上添加方法,表示對外輸出的接口,如同在module.exports上添加同樣。注意,不能直接將exports變量指向一個值,由於這樣等於切斷了exports與module.exports的聯繫。blog

module.exports

module.exports 對象是由模塊系統建立的。 有時這是難以接受的;許多人但願他們的模塊成爲某個類的實例。 爲了實現這個,須要將指望導出的對象賦值給 module.exports。 注意,將指望的對象賦值給 exports 會簡單地從新綁定本地 exports 變量,這可能不是指望的。接口

例子,假設建立了一個名爲 a.js 的模塊:事件

const EventEmitter = require('events');

module.exports = new EventEmitter();

// 處理一些工做,並在一段時間後從模塊自身觸發 'ready' 事件。
setTimeout(() => {
  module.exports.emit('ready');
}, 1000);

而後,在另外一個文件中能夠這麼作:內存

const a = require('./a');
a.on('ready', () => {
  console.log('模塊 a 已準備好');
});

注意,對 module.exports 的賦值必須當即完成。 不能在任何回調中完成。 如下是無效的:

x.js:

setTimeout(() => {
  module.exports = { a: 'hello' };
}, 0);

y.js:

const x = require('./x');
console.log(x.a);

exports

exports 變量是在模塊的文件級別做用域內有效的,它在模塊被執行前被賦予 module.exports 的值。

它有一個快捷方式,以便 module.exports.f = ... 能夠被更簡潔地寫成 exports.f = ...。 注意,就像任何變量,若是一個新的值被賦值給 exports,它就再也不綁定到 module.exports

module.exports.hello = true; // 從對模塊的引用中導出
exports = { hello: false };  // 不導出,只在模塊內有效

當 module.exports 屬性被一個新的對象徹底替代時,也會從新賦值 exports,例如:

module.exports = exports = function Constructor() {
  // ... 及其餘
};

爲了解釋這個行爲,想象對 require() 的假設實現,它跟 require() 的實際實現至關相似:

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    // 模塊代碼在這。在這個例子中,定義了一個函數。
    function someFunc() {}
    exports = someFunc;
    // 此時,exports 再也不是一個 module.exports 的快捷方式,
    // 且這個模塊依然導出一個空的默認對象。
    module.exports = someFunc;
    // 此時,該模塊導出 someFunc,而不是默認對象。
  })(module, module.exports);
  return module.exports;
}

demo.js:

console.log(exports); // {}
console.log(module.exports); // {}
console.log(exports === module.exports); // true
console.log(exports == module.exports); // true
console.log(module);
/**
Module {
id: '.',
exports: {},
parent: null,
filename: '/Users/ring/Desktop/demo.js',
loaded: false,
children: [],
paths:
[ '/Users/ring/Desktop/node_modules',
'/Users/ring/node_modules',
'/Users/node_modules',
'/node_modules' ] }
*/

注意

每一個js文件一建立,都有一個var exports = module.exports = {} , 使exports和module.exports都指向一個空對象。

module.exports和exports所指向的內存地址相同

相關文章
相關標籤/搜索