Javascript 为什么我导出的函数不是函数?

Javascript 为什么我导出的函数不是函数?,javascript,node.js,Javascript,Node.js,考虑以下示例: // bar.js const foo = require('./foo'); module.exports = function(args){ let f = foo(args) } // foo is not a function 然后: foo.js看起来像: const bar = require('./bar'); module.exports = function(args){ //same args as bar.js const f

考虑以下示例:

// bar.js
const foo = require('./foo');    

module.exports = function(args){
    let f = foo(args)
}
// foo is not a function
然后:

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
};

您正在处理循环依赖的问题。我猜
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={}
    ),所以将
    bar.js
    中的
    foo
    设置为
    A={}
    (这就是问题所在!)
  • 用声明的函数替换导出的
    bar.js
  • 用声明的函数替换
    foo.js
    的导出
  • 如您所见,如果使用循环依赖项,VM无法跟踪
    bar.js
    foo.js
    的导出

    在第二个示例中,稍后在调用函数时解析
    foo.js
    的导出。此时,
    foo.js
    的导出已经被函数替换,并且可以正常工作


    简短的版本:这就是发生的事情

  • VM加载
    foo.js
    ,并使用对象
    A
    初始化
    foo.js
    的导出
  • VM加载
    bar.js
    ,并使用对象
    B
    初始化
    bar.js
    的导出
  • VM将
    bar.js
    中的变量
    foo
    设置为
    foo.js
    的导出,因此
    foo=A
  • VM用函数
    C
    取代了导出的
    bar.js
  • VM将
    foo.js
    中的变量
    bar
    设置为导出
    bar.js
    ,因此
    bar=C
  • VM使用函数
    D
    替换
    foo.js
    的导出
  • 正如您再次看到的,
    bar.js
    中的变量
    foo
    仍然是
    A
    ,即使它应该是
    D


    您通常希望避免使用循环依赖关系。如果确实需要,则不要替换
    模块。导出
    ,而是将属性附加到对象:

    module.exports.doBarAction = function(args){
        let f = foo.doFooAction(args)
    };
    
    这解决了问题,因为对象在运行时仍然是相同的。

    然而,在大多数情况下,最好摆脱循环依赖,至少在我们讨论CommonJS模块时是这样。

    foo的代码肯定不是“不必要的代码”。我更新了更多的问题code@znat是的,这正是我所期望的,关于解释和解决方案,请参阅我的答案。这对于Java程序员来说很难理解:)@znat是的,Java执行静态编译,允许编译器毫无问题地解决循环依赖关系,但JavaScript VM没有。不要试图将
    require()
    import
    进行比较。
    module.exports.doBarAction = function(args){
        let f = foo.doFooAction(args)
    };