module.exports與exports的區別【轉】

寫在前面:本文轉自博友:wbxjiayou的文章node.js中module.export與export的區別。javascript

 

對module.exports和exports的一些理解

多是有史以來最簡單通俗易懂的有關Module.exports和exports區別的文章了。html

exports = module.exports = {};java

因此module.exportsexports的區別就是var a={}; var b=a;,a和b的區別node

看起來木有什麼太大區別,但實際用起來的時候卻又有區別,這是爲啥呢,請聽我細細道來api

關於Module.exports和exports有什麼區別,網上一搜一大把,可是說的都太複雜了…
據說exports是Module.exports對象的一個引用(reference)^1,什麼是引用?!…_(:з」∠)_函數

固然啦,若是要完全理解這兩個導出的區別,最好確定是去看源碼,看看都是怎麼封裝的,功力深厚的童鞋應該一看就懂了。不過,源碼我也是看不懂的…(ಥ_ಥ)post

可是最近感受雜七雜八看了好多文章作了好多實驗以後,像是打開了任督二脈,機智的我好像有點上道了…ui

module

首先要明確的一點,module是一個對象 {Object}
當你新建一個文件,好比mo.js,文件內容以下:url

1
console.log(module);

 

而後在CMD裏執行這個文件node mo.js,就能看到module實際上是一個Module實例,你能夠這麼理解,NodeJS中定義了一個Module類,這個類中有不少屬性和方法,exports是其中的一個屬性:spa

1
2
3
4
5
function Module {
id : 'blabla',
exports : {},
blabla...
}

 

當每一個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.exportsexports混用是徹底能夠的,這種狀況下,感受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.exportsexports的區別就是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對象上,不要和導出屬性值混在一塊兒
相關文章
相關標籤/搜索