Node.js遵循CommonJS規範的模組機制,一個JS檔案即被視為一個獨立的模組。在模組內部可以通過2種方式匯出模組:
- module.exports
- exports
module.exports是一個物件引用,這個物件具有以下特徵:
- 預設值:{}
- 模組始終匯出該物件
exports也是一個物件引用,它與module.exports預設指向同一個物件
console.log(module.exports === exports); // true
複製程式碼
所以如果我們只是向module.exports(或exports)追加需要匯出的內容時,採用哪種方式都可以,因為兩者始終指向同一個物件
module.exports.a = 1;
console.log(module.exports); // { a: 1 }
console.log(exports); // { a: 1 }
exports.b = 2;
console.log(module.exports); // { a: 1, b: 2 }
console.log(exports); // { a: 1, b: 2 }
複製程式碼
但如果給module.exports(或exports)重新賦值,那麼就會出現一些意想不到的效果。假設我們使用如下的方式匯出模組
// foo.js
module.exports = {
a: 1
}
exports.b = 2;
複製程式碼
// main.js
var foo = require('./foo');
console.log(foo); // { a: 1 },匯出的物件並不包含b
複製程式碼
出現上面結果的原因是:module.exports
在被’=’賦值時,實際上是新生成了一個{a: 1}
物件,並且斷開module.exports
與預設物件{}
的引用,從而指向{a: 1}
這個新生成的物件;然而exports
此時還是指向預設物件{}
,exports.b = 2;
實際上是向這個預設物件新增了b
,而不是module.exports
所指的那個物件;並且Node模組最終只會匯出module.exports所指向的那個物件(或值),所以就出現了上面的結果。
概括一句話就是:給模組物件的重新複製導致module.exports與exports分別指向了不同的物件
‘最好的證明就是用程式碼演示’,所以我們程式碼證明一下上面的分析
// foo.js
module.exports = {
a: 1
}
exports.b = 2;
console.log(module.exports === exports); // false
console.log(module.exports); // { a: 1 }
console.log(exports); // { b: 2 }
複製程式碼
// main.js
var foo = require('./foo');
console.log(foo); // { a: 1 }
複製程式碼
那麼是否有辦法修補上面的問題呢?答案是:有的,問題的關鍵是:module.exports與exports指向了不同的物件,那麼我們就將它們指回同一個物件
// foo.js
module.exports = {
a: 1
}
console.log(module.exports === exports); // false
exports = module.exports;
exports.b = 2;
console.log(module.exports === exports); // true
console.log(module.exports); // { a: 1, b: 2 }
console.log(exports); // { a: 1, b: 2 }
複製程式碼
所以,匯出模組時我們最好採用如下形式:
exports = module.exports = {
a: 1
}
console.log(module.exports === exports); // true
console.log(module.exports); // { a: 1 }
console.log(exports); // { a: 1 }
複製程式碼
以上就是對module.exports與exports兩者關係的淺顯分析,希望對大家有所幫助,如有錯誤,歡迎指正~