为什么跨模块的相互依赖函数在运行时在节点 javascript 中评估为未定义
why do interdepedent functions across modules evaluate to undefined at runtime in node javascript
我有三个 javascript 个文件
moduleA.js
、moduleB.js
和 index.js
moduleA.js
const {b1} = require('./moduleB');
const a1 = ()=>{
console.log('a1 called')
};
const a2 = ()=>{
console.log('a2 called');
b1()
};
module.exports = {a1, a2};
moduleB.js
const {a1} = require('./moduleA');
const b1 = () => {
console.log('b1 called');
a1();
};
const b2 = () => {
console.log('b2 called');
};
module.exports = {b1, b2};
index.js
const {a2} = require('./moduleA');
a2();
为什么调用 a2()
会在运行时抛出错误,因为 a2
在节点中是 undefined
?我还没有在其他语言中看到这种类型的错误,例如 Java.
除了将 a2
放入另一个文件(例如 moduleC.js
并调用 moduleC.a2()
之外,是否有其他解决方案?
当前输出为:
TypeError: a1 is not a function
at b1 (... /moduleB.js:5:5)
at a2 (... /moduleA.js:7:5)
预期输出为
// a2 called
// b1 called
// a1 called
附加信息
基于 Felix 提供的公认答案以及我对 Matt Frisbie 的 Professional JavaWeb Developers[=] 中 Modules 章节的理解67=]。我画这张图是为了帮助我理解 CommonJS 中的模块加载过程。我希望将来遇到这个问题的人会发现它和我一样有用。
如评论中所述,错误是a1
是undefined
,而不是a2
。原因是模块 A 和模块 B 之间存在循环依赖关系。
当模块 B 从模块 A 导入 a1
时,模块 A 的 exports
对象仍然是空的,即 a1
还不存在。
要解决此问题,您需要做两件事:
- 延迟访问
a1
直到需要它(这是在评估所有模块之后)。
- 不要覆盖初始导出对象,而是更新它。
const a = require('./moduleA');
// ^^^
const b1 = () => {
console.log('b1 called');
a.a1();
// ^^
};
const b2 = () => {
console.log('b2 called');
};
module.exports = {b1, b2};
const {b1} = require('./moduleB');
exports.a1 = ()=>{
console.log('a1 called')
};
exports.a2 = ()=>{
console.log('a2 called');
b1()
};
或者当然重构您的代码,使其不使用循环依赖。
我有三个 javascript 个文件
moduleA.js
、moduleB.js
和 index.js
moduleA.js
const {b1} = require('./moduleB');
const a1 = ()=>{
console.log('a1 called')
};
const a2 = ()=>{
console.log('a2 called');
b1()
};
module.exports = {a1, a2};
moduleB.js
const {a1} = require('./moduleA');
const b1 = () => {
console.log('b1 called');
a1();
};
const b2 = () => {
console.log('b2 called');
};
module.exports = {b1, b2};
index.js
const {a2} = require('./moduleA');
a2();
为什么调用 a2()
会在运行时抛出错误,因为 a2
在节点中是 undefined
?我还没有在其他语言中看到这种类型的错误,例如 Java.
除了将 a2
放入另一个文件(例如 moduleC.js
并调用 moduleC.a2()
之外,是否有其他解决方案?
当前输出为:
TypeError: a1 is not a function
at b1 (... /moduleB.js:5:5)
at a2 (... /moduleA.js:7:5)
预期输出为
// a2 called
// b1 called
// a1 called
附加信息
基于 Felix 提供的公认答案以及我对 Matt Frisbie 的 Professional JavaWeb Developers[=] 中 Modules 章节的理解67=]。我画这张图是为了帮助我理解 CommonJS 中的模块加载过程。我希望将来遇到这个问题的人会发现它和我一样有用。
如评论中所述,错误是a1
是undefined
,而不是a2
。原因是模块 A 和模块 B 之间存在循环依赖关系。
当模块 B 从模块 A 导入 a1
时,模块 A 的 exports
对象仍然是空的,即 a1
还不存在。
要解决此问题,您需要做两件事:
- 延迟访问
a1
直到需要它(这是在评估所有模块之后)。 - 不要覆盖初始导出对象,而是更新它。
const a = require('./moduleA');
// ^^^
const b1 = () => {
console.log('b1 called');
a.a1();
// ^^
};
const b2 = () => {
console.log('b2 called');
};
module.exports = {b1, b2};
const {b1} = require('./moduleB');
exports.a1 = ()=>{
console.log('a1 called')
};
exports.a2 = ()=>{
console.log('a2 called');
b1()
};
或者当然重构您的代码,使其不使用循环依赖。