CommonJS 中 module.exports 和 exports 有什么区别?
请说明 CommonJS 中 module.exports 和 exports 的关系,以及为什么直接给 exports 赋值会失效。
回答
我是大山
本质:在 CommonJS 中,module.exports 和 exports 最初指向同一个对象引用:
// 内部实现大致如下
const module = { exports: {} };
const exports = module.exports;
正确用法:
// 方式一:给 exports 添加属性(推荐)
exports.add = (a, b) => a + b;
exports.sub = (a, b) => a - b;
// 等价于 module.exports.add = ...
// 方式二:直接赋值 module.exports
module.exports = {
add: (a, b) => a + b,
sub: (a, b) => a - b
};
错误用法:
// ❌ 直接给 exports 赋值会切断引用
exports = {
add: (a, b) => a + b
};
// 此时 exports 不再指向 module.exports
// require 时得到的是空对象 {}
原因:
exports只是一个局部变量,初始值为module.exports的引用- 给
exports重新赋值只是改变了局部变量的指向,不影响module.exports require()返回的是module.exports的值
最佳实践:
- 添加属性时用
exports.name = ... - 导出单个函数/类/对象时用
module.exports = ...(此时不应再用exports) - 避免混用:一旦使用
module.exports = ...,exports上的属性会被忽略
Node.js 源码简化:
function require(file) {
const module = { exports: {} };
const exports = module.exports; // 两者指向同一对象
(function(exports, require, module, __filename, __dirname) {
// 用户代码在这里执行
exports = { changed: true }; // ❌ 不影响 module.exports
})(exports, require, module);
return module.exports; // 空对象
}