您现在的位置是:网站首页 > module.exports与exports的区别文章详情

module.exports与exports的区别

在 Node.js 中,module.exportsexports 是模块系统的核心概念,但它们的区别常常让人困惑。理解它们的关系和用法对编写模块化代码至关重要。

module.exports 与 exports 的关系

module.exports 是模块系统实际导出的对象,而 exports 只是对 module.exports 的一个引用。初始状态下,exportsmodule.exports 指向同一个空对象 {}。这意味着:

console.log(exports === module.exports); // true

当直接给 exports 赋值时,这种引用关系会被破坏。例如:

exports = { a: 1 };
console.log(module.exports); // 输出 {},而不是 { a: 1 }

这是因为 exports 被重新赋值,指向了新对象,而 module.exports 仍然指向原来的空对象。

正确使用 exports

exports 的正确用法是通过添加属性或方法,而不是直接赋值:

exports.a = 1;
exports.b = function() { return 2; };
console.log(module.exports); // 输出 { a: 1, b: [Function] }

这种方式不会破坏 exportsmodule.exports 的引用关系,因此修改会反映到 module.exports 上。

直接使用 module.exports

当需要导出一个函数、类或特定对象时,直接操作 module.exports 更可靠:

// 导出一个函数
module.exports = function() {
  return 'Hello World';
};

// 导出一个类
module.exports = class MyClass {
  constructor(name) {
    this.name = name;
  }
};

// 导出一个特定对象
module.exports = {
  version: '1.0.0',
  sayHello: function() {
    console.log('Hello');
  }
};

常见误区与示例

一个常见错误是混用 exportsmodule.exports

exports.a = 1;
module.exports = { b: 2 };
// 最终导出的是 { b: 2 },a 被丢弃

另一个误区是认为 exports 可以独立使用:

exports = function() {}; // 无效
// 必须使用 module.exports = function() {};

模块导出模式

Node.js 中常见的导出模式包括:

  1. 添加属性模式(适合导出多个成员):
exports.func1 = function() {};
exports.func2 = function() {};
  1. 对象字面量模式
module.exports = {
  func1: function() {},
  func2: function() {}
};
  1. 构造函数/类模式
function MyClass() {}
module.exports = MyClass;
  1. 函数模式
module.exports = function(config) {
  // 返回一个对象
  return {
    method: function() {}
  };
};

实际应用场景

在大型项目中,通常会看到这样的结构:

// user.js
function getUser() {
  // ...
}

function createUser() {
  // ...
}

module.exports = {
  getUser,
  createUser
};

// 或者
exports.getUser = getUser;
exports.createUser = createUser;

而在导出单例或配置时:

// config.js
module.exports = {
  dbUrl: 'mongodb://localhost:27017',
  port: 3000
};

循环依赖中的表现

当模块之间存在循环依赖时,理解导出机制尤为重要:

// a.js
exports.x = 'a1';
require('./b');
exports.y = 'a2';

// b.js
const a = require('./a');
console.log(a.x); // 'a1'
console.log(a.y); // undefined

这是因为 b.jsa.js 完全导出前就加载了它,此时 y 尚未被添加。

ES Modules 的对比

随着 ES Modules 的普及,对比一下:

// CommonJS
exports.a = 1;
module.exports.b = 2;

// ES Modules
export const a = 1;
export default { b: 2 };

关键区别在于 ES Modules 的导出是静态的,而 CommonJS 是动态的。

性能考量

虽然 exportsmodule.exports 的性能差异可以忽略不计,但在热路径代码中,直接使用 module.exports 可能略微高效,因为它减少了一次引用解析。

历史背景

exports 的存在主要是为了提供更简洁的 API。早期 Node.js 文档鼓励使用 exports 来添加属性,而保留 module.exports 用于特殊情况下的覆盖操作。

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步