CommonJS 里的 `module.exports` vs `exports`:为什么给后者重新赋值会失效?

技术讲座:CommonJS 中 module.exportsexports 的区别与使用

引言

CommonJS 是 Node.js 中使用的一种模块化规范,它允许开发者将代码分割成多个模块,方便管理和复用。在 CommonJS 中,module.exportsexports 是两个非常关键的属性,但它们的使用方式和作用域却有所不同。本文将深入探讨这两个属性的区别,并分析为什么给 exports 重新赋值会失效。

CommonJS 模块化简介

在 CommonJS 中,每个文件都是一个模块,通过 requiremodule.exports 实现模块的导入和导出。模块可以导出变量、函数、对象等,供其他模块使用。

// moduleA.js
const a = 1;
const b = 2;

module.exports = {
  a,
  b
};
// moduleB.js
const { a, b } = require('./moduleA');
console.log(a, b); // 输出:1 2

module.exportsexports 的区别

module.exports

module.exports 是模块的默认导出对象,用于导出模块的属性、方法或对象。它是一个引用类型,因此导出的内容可以是一个对象、数组或函数等。

// moduleA.js
const a = 1;
const b = 2;

module.exports = {
  a,
  b
};

在上面的代码中,module.exports 被赋值为一个包含 ab 属性的对象。这意味着在 moduleB.js 中导入 moduleA 后,可以访问到 ab 属性。

exports

exports 是模块的局部变量,其作用域仅限于当前模块。在模块初始化时,exportsmodule.exports 是同一个对象。因此,直接给 exports 赋值,实际上是在修改 module.exports

// moduleA.js
const a = 1;
const b = 2;

exports.a = a;
exports.b = b;

在上面的代码中,exports 被赋值为一个包含 ab 属性的对象。这意味着在 moduleB.js 中导入 moduleA 后,可以访问到 ab 属性。

为什么给 exports 重新赋值会失效?

虽然 exportsmodule.exports 在模块初始化时指向同一个对象,但它们的行为有所不同。当我们给 exports 重新赋值时,实际上是在修改 exports 本身,而不是 module.exports

以下是一个示例:

// moduleA.js
const a = 1;
const b = 2;

exports.a = a;
exports.b = b;

// 重新赋值 exports
exports = {
  c: 3
};

在上述代码中,我们首先给 exports 赋值了一个包含 abc 属性的对象。然后,我们再次给 exports 赋值,这次赋值的是一个只包含 c 属性的对象。由于 exportsmodule.exports 已经指向同一个对象,重新赋值 exports 并不会影响 module.exports,因此 moduleA.js 中导出的 ab 属性将不会生效。

解决方法

为了避免给 exports 重新赋值导致的问题,我们可以在模块初始化时直接使用 module.exports 来导出模块属性。

// moduleA.js
const a = 1;
const b = 2;

module.exports = {
  a,
  b
};

这样,无论我们如何修改 exports,都不会影响 module.exports,从而确保模块的属性能够正确导出。

总结

在 CommonJS 中,module.exportsexports 是两个重要的属性,但它们的使用方式和作用域有所不同。给 exports 重新赋值会导致模块属性失效,因此建议使用 module.exports 来导出模块属性。本文深入探讨了这两个属性的区别,并提供了相应的解决方案,希望能帮助开发者更好地理解和使用 CommonJS 模块化规范。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注