徹底搞懂Node.js中exports與module.exports的區別

weixin_33860722發表於2018-08-27

先看個例子 A:

let a={name:"chen"}
let b= a  //b{name:"chen"}

b 淺拷貝了 a,可以說 b 是 a 的引用,因為它們指向了同一個記憶體地址,它們相互影響。但是!當 b=function bb(){xxx} 後,b就不指向 a 的記憶體地址了,也就是說,b 不再是a 的引用了,從這之後,b的改變不會影響a,a的改變(a 永遠是一個物件)也不會影響b


exports:
(1)它最初是一個可以新增屬性的空物件。
(2)它是 module.exports 的全域性引用
(3)如例子 A 所說,當用其他物件、函式或變數給 exports 賦值,那麼 exports 就不再是 module.exports 的引用,換句話說,會導不出來所需要的函式、變數,導致報錯。

如例子 B:

currency.js:

function oneToTwo() {
  console.log("222")
}
function oneToThree() {
  console.log("333")
}
//這裡將一個函式方法賦值給 exports,
//導致 exports 不再是 module.exports 的引用
exports=oneToTwo

testCurrency.js:

let Currency=require("./currency")
//因為匯出的是 module.exports 而不是 export,
//而不再是 module.exports 引用的 exports 沒有改變 module.exports 的值,
//所以 module.exports 的值仍為初始值 {}
console.log(Currency) // {}

module.exports:
(1)程式匯出的永遠是 module.exports
(2)如果你建立了 既有 exports 又有 module.exports 的模組,那它會返回 module.exports
(3)如果 exports 不再是 module.exports 的引用,使用如下方法,重新保持兩者的連線

module.exports=exports=oneToTwo

或者

exports=module.exports=oneToTwo

注意:當你在 currency.js(上面提到的檔案)寫

exports.oneToTwo=oneToTwo

的時候,這個 exports 不是 exports,不是做 module.exports 引用的那個 exports,而是 module.exports,這個 exports.oneToTwo 是 module.exports.oneToTwo 的簡寫


是不是很搞,很煩?我也覺得很搞,那麼問題來了:
為什麼要拿一個 exports 來做 module.exports 的引用?而不是直接使用 module.exports ?

我現在也還未明白,看了這篇博文(https://cnodejs.org/topic/52308842101e574521c16e06),原話是說「其實,當我們瞭解到原理後,不難明白這樣的寫法有點冗餘,其實是為了保證,模組的初始化環境是乾淨的。同時也方便我們,即使改變了 module.exports 指向的物件後,依然能沿用 exports的特性


最後用官方的一句話,簡述兩者區別:
If you want the root of your module’s export to be a function (such as a constructor) or if you want to export a complete object in one assignment instead of building it one property at a time, assign it to module.exports instead of exports.
如果希望模組匯出的是其他物件、函式或變數,那麼用 module.exports 而不是 exports

歡迎關注本公眾號:

5518628-d2bb5f90d86745f0

(完)

相關文章