Object.assign(module.exports, {...}) 与 module.exports = {...}
Object.assign(module.exports, {...}) vs module.exports = {...}
有人可以举例说明 module.exports = {...} 将如何导致意外行为。
我读到你还不了解 js,我在
https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch8.md#node-commonjs-modules
Some developers have the habit of replacing the default exports
object, like this:
// defining a new object for the API
module.exports = {
// ..exports..
};
There are some quirks with this approach, including unexpected
behavior if multiple such modules circularly depend on each other. As
such, I recommend against replacing the object. If you want to assign
multiple exports at once, using object literal style definition, you
can do this instead:
Object.assign(module.exports,{
// .. exports ..
});
What's happening here is defining the { .. } object literal with your
module's public API specified, and then Object.assign(..) is
performing a shallow copy of all those properties onto the existing
module.exports object, instead of replacing it This is a nice balance
of convenience and safer module behavior.
在你的模块运行之前为你的模块创建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);
当您 运行 时:
main starting
a starting
b starting
in b, a.done = undefined
b done
in a, b.done = true
a done
in main, a.done = undefined, b.done = true
(node:2025) Warning: Accessing non-existent property 'done' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
旁注:JavaScript 自己的模块系统 (ESM) 对循环的处理方式不同,并且由于没有 exports
等效对象(您可以访问;概念上有),这问题不会出现。我建议尽可能使用 ESM。 Node.js 自 v12.
以来以相当稳定(尽管仍在发展)的方式支持它
有人可以举例说明 module.exports = {...} 将如何导致意外行为。
我读到你还不了解 js,我在 https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch8.md#node-commonjs-modules
Some developers have the habit of replacing the default exports object, like this:
// defining a new object for the API module.exports = { // ..exports.. };
There are some quirks with this approach, including unexpected behavior if multiple such modules circularly depend on each other. As such, I recommend against replacing the object. If you want to assign multiple exports at once, using object literal style definition, you can do this instead:
Object.assign(module.exports,{ // .. exports .. });
What's happening here is defining the { .. } object literal with your module's public API specified, and then Object.assign(..) is performing a shallow copy of all those properties onto the existing module.exports object, instead of replacing it This is a nice balance of convenience and safer module behavior.
在你的模块运行之前为你的模块创建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);
当您 运行 时:
main starting a starting b starting in b, a.done = undefined b done in a, b.done = true a done in main, a.done = undefined, b.done = true (node:2025) Warning: Accessing non-existent property 'done' of module exports inside circular dependency (Use `node --trace-warnings ...` to show where the warning was created)
旁注:JavaScript 自己的模块系统 (ESM) 对循环的处理方式不同,并且由于没有 exports
等效对象(您可以访问;概念上有),这问题不会出现。我建议尽可能使用 ESM。 Node.js 自 v12.