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两者关系的浅显分析,希望对大家有所帮助,如有错误,欢迎指正~