CodeWalk

CommonJS 中 module.exports 和 exports 有什么区别?

作者:我是大山 · 2026-05-30 12:55

请说明 CommonJS 中 module.exports 和 exports 的关系,以及为什么直接给 exports 赋值会失效。

回答

我是大山

本质:在 CommonJS 中,module.exportsexports 最初指向同一个对象引用

// 内部实现大致如下
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; // 空对象
}