對module.exports和exports的一些理解
可能是有史以來最簡單通俗易懂的有關Module.exports和exports區別的文章了。
exports = module.exports = {};
所以module.exports
和exports
的區別就是var a={}; var b=a;
,a和b的區別
看起來木有什么太大區別,但實際用起來的時候卻又有區別,這是為啥呢,請聽我細細道來
關於Module.exports和exports有什么區別,網上一搜一大把,但是說的都太復雜了…
聽說exports是Module.exports對象的一個引用(reference)^1,什么是引用?!…_(:з」∠)_
當然啦,如果要徹底理解這兩個導出的區別,最好肯定是去看源碼,看看都是怎么封裝的,功力深厚的童鞋應該一看就懂了。不過,源碼我也是看不懂的…(ಥ_ಥ)
但是最近感覺雜七雜八看了好多文章做了好多實驗之后,像是打開了任督二脈,機智的我好像有點上道了…
module
首先要明確的一點,module是一個對象 {Object}
。
當你新建一個文件,比如mo.js,文件內容如下:
1 |
console.log(module); |
然后在CMD里執行這個文件node mo.js
,就能看到module其實是一個Module實例,你可以這么理解,NodeJS中定義了一個Module類,這個類中有很多屬性和方法,exports是其中的一個屬性:
1 |
function Module { |
當每個js文件在執行或被require的時候,NodeJS其實創建了一個新的實例var module = new Module()
,這個實例名叫module
。
這也就是為什么你並沒有定義module
這個變量,卻能console.log出來而不會報錯的原因。
module.exports
假設我有一個JS文件內容如下:
console.log(module); //你會看到Module中的exports為空對象{} module.exports = { print : function(){console.log(12345)} } console.log(module); //你會看到Module中的exports對象已經有了print()方法
有了上面的基礎,很容易理解module.export
其實是給Module實例中的exports對象中添加方法/屬性。
exports
通常使用exports的時候,是這么用的:
exports.print = function(){console.log(12345)}
假設我有一個JS文件內容如下:
console.log(module); //你會看到Module中的exports為空對象{} console.log(exports); //你會看到Module中的exports為空對象{} module.exports = { print : function(){console.log(12345)} } console.log(module); //你會看到Module中的exports對象有了print()方法 exports.name = '小白妹妹'; console.log(module); //你會看到Module中的exports對象不僅有了print()方法,還有了name屬性
由此也能看出,傳說中的exports
其實是module.exports
的引用,你可以這么理解,NodeJS在你的代碼之前悄悄的加了以下代碼:
var module = new Module();
var exports = module.exports;
這也就是為什么你並沒有定義exports
這個變量,卻能console.log出來而不會報錯的原因。
require
當你從外部調用某個模塊,require其實是在require什么?^2
require的時候NodeJS會到處去找有沒有這個模塊,如果有,return的就是module.exports里的東東。
DOs & DONTs
- √你可以這樣:
如果只是使用module.exports.name = '小白妹妹'; exports.age = 10; module.exports.print = function(){console.log(12345)};
.
來添加屬性和方法,module.exports
和exports
混用是完全可以的,這種情況下,感覺exports
就是給懶人用的…畢竟能少寫幾個7個字符呢! - √也可以這樣:
module.exports = { name = '小白妹妹'; }; exports.age = 10; module.exports.print = function(){console.log(12345)};
- ×但不可以這樣:
module.exports = { name = '小白妹妹'; }; exports = {age:10}; // exports現在是{age:10}這個對象的引用,不再是module.exports的引用了 console.log(module); //你會看到Module的exports中只有name屬性!!!
- ×也不可以這樣:
exports.age = 10; console.log(module); //你會看到Module的exports中多了age屬性 module.exports = { name = '小白妹妹'; }; console.log(module); //你會看到Module的exports中還是只有name屬性!!!
總結
還是那一句話,module.exports
和exports
的區別就是var a={}; var b=a;
,a和b的區別- 改變
exports
的指向后所添加的exports.xxx
都是無效的。因為require返回的只會是module.exports
- 改變
- 不能在使用了
exports.xxx
之后,改變module.exports
的指向。因為exports.xxx
添加的屬性和方法並不存在於module.exports
所指向的新對象中。 - 對於要導出的屬性,可以簡單直接掛到
exports
對象上 - 對於類,為了直接使導出的內容作為類的構造器可以讓調用者使用new操作符創建實例對象,應該把構造函數掛到
module.exports
對象上,不要和導出屬性值混在一起
感覺自己說的還是挺清楚噠~
不管你清不清楚,我反正是清楚了。_(:з」∠)_