Javascript ES6模块与循环依赖

Javascript ES6模块与循环依赖,javascript,module,ecmascript-6,circular-dependency,es6-modules,Javascript,Module,Ecmascript 6,Circular Dependency,Es6 Modules,在Babel环境中,我在ES6中遇到了这个问题: // A.js class A { } export default new A(); // B.js import C from './C'; class B { } export default new B(); // C.js import A from './A'; import B from './B'; class C { constructor(A, B){ this.A = A; thi

在Babel环境中,我在ES6中遇到了这个问题:

// A.js
class A {
}
export default new A();

// B.js
import C from './C';
class B {
}
export default new B();

// C.js
import A from './A';
import B from './B';
class C {
    constructor(A, B){
        this.A = A;
        this.B = B; // undefined
    }
}
export default new C(A, B)
我这样导入它们:

// stores/index.js
import A from './A';
import B from './B';
import C from './C';

export {
    A,
    B,
    C
}
从我的应用程序入口点,我会:

import * as stores from './stores'; 
我(希望)希望执行顺序是A->B->C,但实际上是A->C->B。
这是由于模块B导入了C,因此C模块在B模块之前进行评估。这会在C的设置中产生问题,因为在这种情况下,B未定义

我看到过类似的解决方案,但我不确定init函数是否是这里的最佳解决方案,它似乎有点粗糙

Q:解决ES6中可能在不同环境中工作的这种循环依赖关系的最佳实践是什么

ES6中循环依赖的最佳实践是什么

完全避免它们。如果您不能(或不想)完全避免它们,请将涉及的模块限制为仅使用具有循环依赖关系的函数声明,切勿使用导入的值(包括
扩展
引用)初始化顶级值(常量、变量、类)

什么可能在不同的环境中工作(Babel、Rollup)

ES6规范中定义了模块解析和初始化的顺序,因此在所有ES6环境中都应该是相同的-无论模块如何加载以及它们的标识符如何解析

如何解决这种循环依赖设置

如果您确实有一个循环依赖项
X->Y->Z->…->X->…
,则需要建立一个起点。假设您希望先加载
X
,但这取决于
Y
,因此您需要确保
X
在圆中的所有模块完全初始化之前,从不使用任何导入的值。因此,您打破了
X
Y
之间的圆圈,您需要在
Y
处启动导入链-它将递归地遍历依赖项,直到它在
X
处停止,该依赖项没有其他尚未初始化的依赖项,因此它将是第一个要评估的模块

然后,您必须遵循的规则是,在导入圆中的任何其他模块之前,始终导入
Y
。如果你甚至有一次不使用这个共同的单一入口点,你的纸牌屋就会倒塌

在您的特定示例中,这意味着
index.js
将需要使用

import A from './A';
import C from './C'; // entry point to circular dependencies
import B from './B';
…

预期执行顺序为A->B->C-哪个入口点?如果没有使用C,为什么要在B中导入C?它被使用了,这是一个缺少实现细节的示例。我已经更新了这个问题,添加了入口点,省略了细节,在这里改变了一切。将不存在循环依赖项,因为未使用的导入将被跳过。考虑提供。仅为单例使用类也是反模式的。
new C()
中的
A
B
是未定义的,因为您没有向构造函数传递参数,而不是因为导入不起作用。永远不要导出类的实例。如果您想要单例模块,请不要使用
class
语法。