node.js中exports與module.exports的區別分析

前言

關於Node.js中的exports和module.exports,不少時候都比較容易讓人混淆,弄不清楚二者間的區別。那麼咱們就從頭開始理清這二者之間的關係。javascript

來源

在開發Node.js應用的時候,不少模塊都是須要引入才能使用,可是爲何exports和module.exports咱們沒有引用卻能夠直接使用呢?java

事實上,Node.js應用在編譯的過程當中會對JavaScript文件的內容進行頭尾的封裝。例如:ui

// hello.js
const hello = function () {
	console.log('Hello world');
}
module.exports = {
	hello
}
// 頭尾封裝後的js代碼
(function (exports, require, module, __filename, __dirname) {
    const hello = function () {
        console.log('Hello world');
    }
    module.exports = {
        hello
    }
})
複製代碼

在進行了頭尾封裝以後,各個模塊之間進行了做用域隔離,避免了污染全局變量,同時能夠使每一個模塊在不引入這些變量的狀況下能夠使用它們。這些變量依次爲當前模塊的exports屬性、require()方法、當前模塊自身(module)、在文件系統中的完整路徑、文件目錄。spa

區別

按照Node.js的解釋,exports是module對象的一個屬性,那麼exports和module.exports應該是等價的。的確如初,初始化的exports和module.exports變量的值均爲{},代碼驗證:code

// hello.js
const hello = function () {
    console.log('Hello world');
}
console.log('初始值==========');
console.log(exports);
console.log(module.exports);
module.exports = {
    hello
}
// 輸出結果
初始值==========
{}
{}
複製代碼

能夠發現,module對象的exports屬性和exports均指向一個空對象{},那麼在導出對象的時候使用exports和module.exports有什麼區別呢?對象

咱們在使用require()方法引入模塊的時候,實際上是引入了module.exports對象, exports只是module對象的exports的一個引用,咱們能夠經過修改exports所指向對象的值來協助修改module.exports的值。ip

  • 使用exports導出
const hello = function () {
    console.log('Hello world');
}
exports.hello = {
    hello
}
console.log('修改值==========');
console.log(exports);
console.log(module.exports);
// 輸出結果
修改值==========
{ hello: { hello: [Function: hello] } }
{ hello: { hello: [Function: hello] } }
複製代碼

因爲exports和module.exports指向同一塊內存區域,因此咱們修改exports對象的數據,那麼module.exports也會隨之改變。內存

  • 使用module.exports導出
// hello.js
const hello = function () {
    console.log('Hello world');
}
module.exports = {
    hello
}
console.log('修改值==========');
console.log(exports);
console.log(module.exports);
// 輸出結果
修改值==========
{}
{ hello: [Function: hello] }
複製代碼

你會發現修改後的exports依然是{},而module.exports的值已經改變,這是因爲當你給module.exports是直接等於一個新的對象,那麼其將指向一塊新的內存區域,而此時exports指向的仍然是以前的內存區域,因此兩者的值會不同,可是此時你在其餘文件內引入hello.js文件,仍然能夠調用hello()方法,這也說明了導出的是module.exports而不是exports。作用域

  • 給exports直接賦值
// hello.js
const hello = function () {
    console.log('Hello world');
}
exports = {
    hello
}
console.log('修改值==========');
console.log(exports);
console.log(module.exports);
// 輸出結果
修改值==========
{ hello: [Function: hello] }
{}
複製代碼

使用這種方法導出在其餘文件調用hello方法即會報錯,由於該文件模塊導出的對象爲空,固然也不可能有hello()方法,這種問題的緣由一樣是指向的內存區域發生變化所致使的。開發

總結

  1. exports對象是module對象的一個屬性,在初始時exports和module.exports是指向同一塊內存區域的;
  2. 在不改變exports內存指向的狀況下,修改exports的值能夠改變module.exports的值;
  3. 導出儘可能使用module.exports以免混淆。
相關文章
相關標籤/搜索