require 用來載入代碼,而 exports 和 module.exports 則用來導出代碼。但很多新手可能會迷惑於 exports 和 module.exports 的區別,為了更好的理解 exports 和 module.exports 的關係,我們先來鞏固下 js 的基礎。 ...
require 用來載入代碼,而 exports 和 module.exports 則用來導出代碼。但很多新手可能會迷惑於 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 結果為:
{ name: 'nswbmw 1' } { name: 'nswbmw 1' } { name: 'nswbmw 2' } { name: 'nswbmw 2' } { name: 'nswbmw 2' } { name: 'nswbmw 3' }
解釋一下: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
。
原文地址:exports 和 module.exports 的區別。