我最近一直在使用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的实例。

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


当前回答

现在不是2015年,大多数库(例如express)已经更新了更好的模式,因此不再需要循环依赖。我建议不要使用它们。

我知道我挖出了一个老答案…… 这里的问题是这个模块。exports定义在您需要ClassB之后。 (JohnnyHK的链接显示) 循环依赖关系在Node中工作得很好,它们是同步定义的。 如果使用得当,它们实际上解决了许多常见的节点问题(比如从其他文件访问express.js应用程序)

只需确保在需要具有循环依赖关系的文件之前定义了必要的导出。

这将打破:

var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet

module.exports = ClassA;

这是可行的:

var ClassA = module.exports = function(){};
var ClassB = require('classB');

我一直使用这个模式来访问其他文件中的express.js应用程序:

var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app

其他回答

懒惰只在你需要的时候才要求呢?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语句将按预期工作。

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

现在不是2015年,大多数库(例如express)已经更新了更好的模式,因此不再需要循环依赖。我建议不要使用它们。

我知道我挖出了一个老答案…… 这里的问题是这个模块。exports定义在您需要ClassB之后。 (JohnnyHK的链接显示) 循环依赖关系在Node中工作得很好,它们是同步定义的。 如果使用得当,它们实际上解决了许多常见的节点问题(比如从其他文件访问express.js应用程序)

只需确保在需要具有循环依赖关系的文件之前定义了必要的导出。

这将打破:

var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet

module.exports = ClassA;

这是可行的:

var ClassA = module.exports = function(){};
var ClassB = require('classB');

我一直使用这个模式来访问其他文件中的express.js应用程序:

var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app

尝试在模块上设置属性。出口,而不是完全取代它。例如,module.exports.instance = a.js中的新ClassA(), module.exports.ClassB = b.js中的ClassB。当你创建循环模块依赖关系时,需要的模块将得到一个不完整模块的引用。从所需的模块导出,您可以稍后添加其他属性,但当您设置整个模块时。导出,你实际上创建了一个新对象,所需的模块没有办法访问。