在 Node.js 中,module.exports 和 exports 都用于向外部暴露模块的公共接口。要理解这两者的区别,首先需要了解 Node.js 的模块系统。
Node.js 中的每个文件都被视为一个独立的模块,每个模块都有自己的作用域。当你在一个模块中声明一个变量,那个变量只在那个模块内部可见,外部无法访问。如果你想让一个模块能够访问另一个模块中的变量,你就需要使用 module.exports 或者 exports。
这两者的工作原理是这样的:
-
每个模块都有一个
module对象,module对象有一个exports属性。这个exports属性就是我们在模块中require一个模块时得到的对象。 -
exports实际上仅仅是对module.exports的一个全局引用,它们最初指向同一个对象。
所以当你要暴露一个模块的公共接口时,你可以选择直接给 module.exports 赋值,或者给 exports 添加属性。这两种方式的效果是一样的,因为 exports 和 module.exports 指向的是同一个对象。
但是,这里有一个重要的区别需要注意:
-
如果你给
module.exports赋值一个新的对象,那么require就会返回这个新的对象。而exports仍然指向原来的对象,此时对exports的任何修改都不会影响到module.exports。 -
相反,如果你给
exports赋值一个新的对象,那么require仍然会返回module.exports指向的原来的对象,因为exports不再指向module.exports。
这里解释一下上述两句话:
1.真正导出的是module.exports,exports只是前者的一个引用;即内部是module.expoerts = exports;(需要认真理解一下这句话)
2.也就是说一旦使用了module.exports = xxx;之后无论你再怎么操作exports都无效了,即module.exports = xxx出现,module.exports和exports就没有切断联系了。
3.注意:当执行exports = 某对象 时,这是切断了module.exports和exports的联系
因此,如果你想要暴露的是一个函数或者一个构造函数,你应该使用 module.exports。如果你想要暴露一个对象,你可以使用 module.exports 或 exports。
这就是为什么我们经常在 Node.js 中看到这样的代码:
module.exports = function() {
// ...
};
或者这样的代码:
exports.myFunction = function() {
// ...
};
但是你很少会看到这样的代码:
exports = function() {
// ...
};
因为这样的代码实际上并没有改变 module.exports,所以 require 时不会得到我们期望的结果。