【问题标题】:Object.assign(module.exports, {...}) vs module.exports = {...}Object.assign(module.exports, {...}) 与 module.exports = {...}
【发布时间】:2020-08-12 07:33:09
【问题描述】:

有人可以举例说明 module.exports = {...} 将如何导致意外行为。

我在读你还不知道 js,我在 https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch8.md#node-commonjs-modules

有些开发者有替换默认导出的习惯 对象,像这样:

// defining a new object for the API
module.exports = {
    // ..exports..
};

这种方法有一些怪癖,包括意想不到的 如果多个这样的模块循环地相互依赖时的行为。作为 这样,我建议不要更换对象。如果你想分配 一次多次导出,使用对象文字样式定义,您 可以这样做:

Object.assign(module.exports,{
   // .. exports ..
});

这里发生的是用你的定义 { .. } 对象字面量 指定模块的公共 API,然后 Object.assign(..) 是 对现有属性执行所有这些属性的浅拷贝 module.exports 对象,而不是替换它这是一个很好的平衡 方便和更安全的模块行为。

【问题讨论】:

  • 很遗憾,他没有提供说明问题的示例。

标签: javascript node.js commonjs


【解决方案1】:

exports 对象是在您的模块运行之前为您的模块创建的,并且 如果 存在循环依赖关系,则其他模块可能会在您的模块填充它之前访问该默认对象。如果你替换它,他们可能有旧的、原始的对象,而不是(最终)看到你的出口。如果您添加它,那么即使该对象最初没有您的导出,最终它也会拥有它,即使其他模块在这些导出存在之前访问该对象。

CJS 模块文档的Cycles section 中的更多内容。

我们可以修改该部分中的循环示例来演示它:

a.js(注意更改):

console.log('a starting');
// Removed: `exports.done = false;`
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports = {done: true}; // ** Modified this line
console.log('a done');

b.js(不变):

console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

main.js(不变):

console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);

当你运行它时:

主启动 一个开始 b 开始 在 b 中,a.done = 未定义 b 完成 在 a, b.done = true 完成 在 main 中,a.done = 未定义,b.done = true (节点:2025)警告:在循环依赖中访问模块导出的不存在属性“完成” (使用 `node --trace-warnings ...` 显示警告的创建位置)

旁注:循环使用 JavaScript 自己的模块系统 (ESM) 以不同方式处理,并且由于没有 exports 等效对象(您可以访问;概念上存在),因此不会出现此问题。我建议尽可能使用 ESM。 Node.js 自 v12 以来一直以相当稳定(尽管仍在不断发展)的方式支持它。

【讨论】:

  • 如果您对 ESM(而不是 CJS)中的循环如何工作感到好奇,我将在新书的第 13 章中深入探讨;如果您有兴趣,请在我的个人资料中链接。
  • 不知道这本书是你写的,必须买。
猜你喜欢
  • 2020-01-13
  • 2017-01-09
  • 1970-01-01
  • 2011-10-31
  • 2016-12-09
  • 1970-01-01
  • 2021-04-08
相关资源
最近更新 更多