考虑以下示例:
// bar.js
const foo = require('./foo');
module.exports = function(args){
let f = foo(args)
}
// foo is not a function
然后:
// bar.js
module.exports = function(args){
let f = require('./foo')(args)
}
// behaves as expected
foo.js看起来像:
const bar = require('./bar');
module.exports = function(args){ //same args as bar.js
const foo = {};
foo.f1 = function(arg){
console.log("Hi")
}
return foo
};
答案 0 :(得分:1)
您正在处理循环依赖的问题。我猜foo.js
看起来像这样:
const bar = require('./bar');
module.exports = function(args) {
console.log(args);
};
让我们按照VM执行代码执行的步骤(假设您先加载foo.js
):
foo.js
。使用A = {}
初始化导出。bar.js
。使用B = {}
初始化导出。现在在bar.js
内:
bar.js
要求导出foo.js
(仍为A = {}
),因此请将foo
中的bar.js
设置为A = {}
(这是问题!)。bar.js
的导出替换为声明的函数。foo.js
的导出替换为声明的函数。如您所见,如果您使用循环依赖关系,则VM无法跟踪foo.js
中bar.js
的导出。
在第二个示例中,稍后在调用函数时解析foo.js
的导出。此时,foo.js
的导出已经被函数替换,并且可以正常工作。
简短版本:这就是发生的事情。
foo.js
并使用对象foo.js
初始化A
的导出。bar.js
并使用对象bar.js
初始化B
的导出。foo
中的变量bar.js
设置为导出foo.js
,因此foo = A
。bar.js
C
的导出
bar
中的变量foo.js
设置为导出bar.js
,因此bar = C
。foo.js
替换D
的导出。正如您所看到的那样,foo
中的变量bar.js
仍为A
,即使它应为D
。
您通常希望避免使用循环依赖。如果确实有必要,那么不要替换module.exports
,而是将属性附加到对象:
module.exports.doBarAction = function(args){
let f = foo.doFooAction(args)
};
这解决了问题,因为对象在运行时仍然是相同的 但是,在大多数情况下,最好摆脱循环依赖,至少只要我们讨论CommonJS模块。