我理解的exports 和 module.exports 的區別,歡迎大家吐槽~
爲了更好的理解
exports
和
module.exports
的關係,我們先來補點 js 基礎。示例:
app.js
var a = {name: 'nswbmw 1'};
var b = a;
console.log(a);
console.log(b);
b.name = 'nswbmw 2';
console.log(a);
console.log(b);
var b = {name: 'nswbmw 3'};
console.log(a);
console.log(b);
運行 app.js 結果爲:
D:\>node app
{ name: 'nswbmw 1' }
{ name: 'nswbmw 1' }
{ name: 'nswbmw 2' }
{ name: 'nswbmw 2' }
{ name: 'nswbmw 2' }
{ name: 'nswbmw 3' }
D:\>
解釋一下:a 是一個對象,b 是對 a 的引用,即 a 和 b 指向同一個對象,即 a 和 b 指向同一塊內存地址,所以前兩個輸出一樣。當對 b 作修改時,即 a 和 b 指向同一塊內存地址的內容發生了改變,所以 a 也會體現出來,所以第三四個輸出一樣。當對 b 完全覆蓋時,b 就指向了一塊新的內存地址(並沒有對原先的內存塊作修改),a 還是指向原來的內存塊,即 a 和 b 不再指向同一塊內存,也就是說此時 a 和 b 已毫無關係,所以最後兩個輸出不一樣。
明白了上述例子後,我們進入正題。我們只需知道三點即可知道
exports
和
module.exports
的區別了:
exports
是指向的module.exports
的引用module.exports
初始值爲一個空對象{}
,所以exports
初始值也是{}
require()
返回的是module.exports
而不是exports
所以:
-
我們通過
var name = 'nswbmw'; exports.name = name; exports.sayName = function() { console.log(name); }
給
exports
賦值其實是給module.exports
這個空對象添加了兩個屬性而已,上面的代碼相當於:var name = 'nswbmw'; module.exports.name = name; module.exports.sayName = function() { console.log(name); }
-
我們通常這樣使用
exports
和module.exports
一個簡單的例子,計算圓的面積:
使用 exports
app.js
var circle = require('./circle'); console.log(circle.area(4));
circle.js
exports.area = function(r) { return r * r * Math.PI; }
使用 module.exports
app.js
var area = require('./area'); console.log(area(4));
area.js
module.exports = function(r) { return r * r * Math.PI; }
上面兩個例子輸出是一樣的。你也許會問,爲什麼不這樣寫呢?
app.js
var area = require('./area'); console.log(area(4));
area.js
exports = function(r) { return r * r * Math.PI; }
運行上面的例子會報錯。這是因爲,前面的例子中通過給
exports
添加屬性,只是對exports
指向的內存做了修改,而exports = function(r) { return r * r * Math.PI; }
其實是對
exports
進行了覆蓋,也就是說exports
指向了一塊新的內存(內容爲一個計算圓面積的函數),也就是說exports
和module.exports
不再指向同一塊內存,也就是說此時exports
和module.exports
毫無聯繫,也就是說module.exports
指向的那塊內存並沒有做任何改變,仍然爲一個空對象{}
,也就是說 area.js 導出了一個空對象,所以我們在 app.js 中調用 area(4) 會報TypeError: object is not a function
的錯誤。所以,一句話做個總結:當我們想讓模塊導出的是一個對象時,
exports
和module.exports
均可使用(但exports
也不能重新覆蓋爲一個新的對象),而當我們想導出非對象接口時,就必須也只能覆蓋module.exports
。 -
我們經常看到這樣的用寫法:
exports = module.exports = somethings
上面的代碼等價於
module.exports = somethings exports = module.exports
原因也很簡單,
module.exports = somethings
是對module.exports
進行了覆蓋,此時module.exports
和exports
的關係斷裂,module.exports
指向了新的內存塊,而exports
還是指向原來的內存塊,爲了讓module.exports
和exports
還是指向同一塊內存或者說指向同一個 “對象”,所以我們就exports = module.exports
。