我最近一直在使用nodejs,仍然在掌握模块系统,所以如果这是一个明显的问题,那么很抱歉。我希望代码大致如下:

A.js(主文件与node一起运行)

var ClassB = require("./b");

var ClassA = function() {
    this.thing = new ClassB();
    this.property = 5;
}

var a = new ClassA();

module.exports = a;

b.js

var a = require("./a");

var ClassB = function() {
}

ClassB.prototype.doSomethingLater() {
    util.log(a.property);
}

module.exports = ClassB;

我的问题似乎是我不能从ClassB的实例中访问ClassA的实例。

有什么正确的/更好的方法来构建模块来实现我想要的? 是否有更好的方法在模块间共享变量?


当前回答

重要的是不要重新分配模块。导出您已经被给予的对象,因为该对象可能已经被给予周期中的其他模块!只需在模块内分配属性。导出和其他模块将看到它们出现。

所以一个简单的解决方案是:

module.exports.firstMember = ___;
module.exports.secondMember = ___;

唯一的缺点是需要重复module.exports。很多次了。


类似于lanzz和setec的回答,我一直在使用以下模式,它感觉更像是声明性的:

module.exports = Object.assign(module.exports, {
    firstMember: ___,
    secondMember: ___,
});

object .assign()将成员复制到已经分配给其他模块的exports对象中。

=赋值在逻辑上是冗余的,因为它只是一个设置模块。出口到自己,但我使用它,因为它帮助我的IDE (WebStorm)识别firstMember是这个模块的属性,所以“转到->声明”(Cmd-B)和其他工具将从其他文件工作。

这个模式不是很漂亮,所以我只在需要解决循环依赖关系问题时使用它。

它非常适合于显示模式,因为您可以轻松地从对象中添加和删除导出,特别是在使用ES6的属性简写时。

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

其他回答

事实上,我最终需要我的依赖

 var a = null;
 process.nextTick(()=>a=require("./a")); //Circular reference!

虽然不漂亮,但很管用。这比更改b.js(例如只增加modules.export)更容易理解和诚实,因为后者是完美的。

懒惰只在你需要的时候才要求呢?b。js是这样的

var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
    var a = require("./a");    //a.js has finished by now
    util.log(a.property);
}
module.exports = ClassB;

当然,将所有require语句放在文件的顶部是一个很好的实践。但在某些情况下,我原谅自己从一个不相关的模块中选择了一些内容。称其为hack,但有时这比引入进一步的依赖项,或添加额外的模块或添加新的结构(EventEmitter等)要好。

这里有一个快速的解决方法,我发现它非常有用。

在文件a.js上

let B;
class A{
  constructor(){
    process.nextTick(()=>{
      B = require('./b')
    })
  } 
}
module.exports = new A();

在文件'b.js'上写以下内容

let A;
class B{
  constructor(){
    process.nextTick(()=>{
      A = require('./a')
    })
  } 
}
module.exports = new B();

这样,在事件循环的下一次迭代中,类将被正确定义,并且那些require语句将按预期工作。

重要的是不要重新分配模块。导出您已经被给予的对象,因为该对象可能已经被给予周期中的其他模块!只需在模块内分配属性。导出和其他模块将看到它们出现。

所以一个简单的解决方案是:

module.exports.firstMember = ___;
module.exports.secondMember = ___;

唯一的缺点是需要重复module.exports。很多次了。


类似于lanzz和setec的回答,我一直在使用以下模式,它感觉更像是声明性的:

module.exports = Object.assign(module.exports, {
    firstMember: ___,
    secondMember: ___,
});

object .assign()将成员复制到已经分配给其他模块的exports对象中。

=赋值在逻辑上是冗余的,因为它只是一个设置模块。出口到自己,但我使用它,因为它帮助我的IDE (WebStorm)识别firstMember是这个模块的属性,所以“转到->声明”(Cmd-B)和其他工具将从其他文件工作。

这个模式不是很漂亮,所以我只在需要解决循环依赖关系问题时使用它。

它非常适合于显示模式,因为您可以轻松地从对象中添加和删除导出,特别是在使用ES6的属性简写时。

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

虽然node.js确实允许循环的require依赖关系,但你已经发现它可能非常混乱,你最好重新构造你的代码以不需要它。也许可以创建第三个类,使用另外两个类来完成您所需要的。