1. 程式人生 > >Node中exports與module.export的使用與區別

Node中exports與module.export的使用與區別

module.exports與exports的介紹

module.exports與exports都是將函式或者是方法暴露出去,require的時候進行呼叫,但是2者是有區別的。以下是程式碼:

複製程式碼
//ex.js

exports='danhuangmode';


//mex.js

  module.exports='danhuangmode';

//call_ex_mex.js

  var ex=require('./ex');
  var mex=require('./mex');

  console.log(ex);
  console.log('\n');
  console.log(mex);

複製程式碼

執行結果:

引用exports提供方法,輸出是為一個物件,引用module.exports提供方法,輸出為字串。

exports內部提供介面,在外部引用時之間的關係如何?

exports內部處理暴露方法,是如何處理的,看如下程式碼:

複製程式碼
var string='this is in exports.js';

 function ex_fn () {
     console.log('this in funtion ex_fn');
}

var exobj={
    str1:"str1 exobj",
    exobjfn: function  () {
        console.log("in function");
    }
};

exports.string=string;
exports.ex_fn
=ex_fn; exports.exobj=exobj; exports=exobj;
複製程式碼

呼叫程式碼:

複製程式碼
var ex=require('./ex');


console.log(ex.string);
console.log(ex.ex_fn);
console.log(ex.exobj);
console.log(ex);
複製程式碼

結果顯示:

exports提供的所有介面,直接呼叫匯出例項化的介面物件,會顯示介面物件中所有提供的型別、函式、物件以及物件中的方法和物件。

module.exports對外提供介面如何處理?

複製程式碼
//mex.js

var ex_fn= function () {
     console.log(
'this in funtion ex_fn'); } module.exports=ex_fn;
複製程式碼

呼叫程式碼mex.js:

複製程式碼
//引用mex.js

var ex=require('./mex');
ex();
console.log(ex);

複製程式碼

執行結果為:

 

 直接將函式作為返回。

再看下面一個例子:

複製程式碼
var person={
    name :"person's name",
    age :20,
    getAge: function  () {
        return this.age;
    }
}

module.exports = person;
複製程式碼

呼叫的程式碼:

複製程式碼
var person=require('./modulex');

console.log(person.name);
console.log(person.age);
console.log(person.getAge());
console.log(person);
複製程式碼

顯示的結果為:

返回為一個json物件,可以直接呼叫內部的函式、屬性。

module.exports 與exports是什麼關係?

module.exports = 'personname';

exports.name=function  () {
    console.log('this is person name');
}

呼叫 的指令碼:

var person=require('./person');

console.log(person);
console.log(person.name);

執行結果:

personname
undefined

結果:

其實真正的介面是module.exports,exports是一個輔助工具。最終返回到是module.exports,而不是exports。

當module.exports沒有任何屬性和方法,exports將收集的所有資訊都傳遞給module.exports,如果module.exports已經具有了屬性和方法,exports所蒐集的資訊將會被忽略。

-------------------------------------------------------------------

第二種解說:

exports = module.exports = {};

所以module.exportsexports的區別就是var a={}; var b=a;,a和b的區別

module

首先要明確的一點,module是一個物件 {Object}
當你新建一個檔案,比如mo.js,檔案內容如下:

1
console.log(module);

然後在CMD裡執行這個檔案node mo.js,就能看到module其實是一個Module例項,你可以這麼理解,NodeJS中定義了一個Module類,這個類中有很多屬性和方法,exports是其中的一個屬性:

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物件上,不要和匯出屬性值混在一起