代码之家  ›  专栏  ›  技术社区  ›  Cinn smfoote

无法从文件复制[

  •  0
  • Cinn smfoote  · 技术社区  · 6 年前

    我最近一直在与nodejs合作,但仍在掌握模块系统,所以如果这是一个明显的问题,我深表歉意。我需要大致如下的代码:

    (主文件与节点一起运行)

    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;
    

    我的问题似乎是我不能从类B的实例中访问类A的实例。

    有没有一种正确/更好的方法来构建模块来实现我想要的? 有没有更好的方法在模块之间共享变量?

    0 回复  |  直到 4 年前
        1
  •  91
  •   JohnnyHK    11 年前

    同时节点.js允许循环 require 依赖关系,就像你发现的那样 pretty messy 你最好重新构造你的代码,这样就不需要它了。也许创建一个第三个类,使用另外两个类来完成您需要的。

        2
  •  183
  •   lanzz    13 年前

    尝试设置属性 module.exports ,而不是完全替换它。例如。, module.exports.instance = new ClassA() 在里面 a.js , module.exports.ClassB = ClassB 在里面 b.js . 当您建立循环模块依赖关系时,需要的模块将获得对不完整的 模块.导出 从所需的模块中,您可以在后面添加其他属性,但是当您设置整个 ,您实际上创建了一个需要模块无法访问的新对象。

        3
  •  55
  •   Will Stern    9 年前

    [编辑]现在不是2015年,大多数图书馆(如express)已经用更好的模式进行了更新,因此不再需要循环依赖。我只推荐 不使用它们 .


    问题是模块.导出定义了 之后 你需要B级。 (约翰尼赫的链接显示) 循环依赖在节点中工作得很好,它们只是同步定义的。 app 从其他文件)

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

    这将打破:

    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');
    

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

    var express = require('express');
    var app = module.exports = express();
    // load in other dependencies, which can now require this file and use app
    
        4
  •  39
  •   Corno    12 年前

    如果确实要替换模块.导出,例如,如果您要创建一个类(如上面示例中的b.js文件),这也是可能的,只需确保在启动循环require的文件中模块.导出=…'语句发生在require语句之前。

    a、 js公司 (主文件与节点一起运行)

    var ClassB = require("./b");
    
    var ClassA = function() {
        this.thing = new ClassB();
        this.property = 5;
    }
    
    var a = new ClassA();
    
    module.exports = a;
    

    var ClassB = function() {
    }
    
    ClassB.prototype.doSomethingLater() {
        util.log(a.property);
    }
    
    module.exports = ClassB;
    
    var a = require("./a"); // <------ this is the only necessary change
    
        5
  •  15
  •   Nicolas Gramlich    10 年前

    解决方案是在需要任何其他控制器之前“转发声明”导出对象。所以,如果你把所有的模块都这样结构,你就不会遇到这样的问题:

    // Module exports forward declaration:
    module.exports = {
    
    };
    
    // Controllers:
    var other_module = require('./other_module');
    
    // Functions:
    var foo = function () {
    
    };
    
    // Module exports injects:
    module.exports.foo = foo;
    
        6
  •  8
  •   Andrew Lavers    8 年前

    一个需要最小变化的解决方案是扩展 module.exports 而不是重写它。

    _ = require('underscore'); //underscore provides extend() for shallow extend
    b = require('./b'); //module `a` uses module `b`
    _.extend(module.exports, {
        do: function () {
            console.log('doing a');
        }
    });
    b.do();//call `b.do()` which in turn will circularly call `a.do()`
    

    b、 js-使用方法do from a.js的模块

    _ = require('underscore');
    a = require('./a');
    
    _.extend(module.exports, {
        do: function(){
            console.log('doing b');
            a.do();//Call `b.do()` from `a.do()` when `a` just initalized 
        }
    })
    

    它将工作并产生:

    doing b
    doing a
    

    虽然此代码不起作用:

    a、 js公司

    b = require('./b');
    module.exports = {
        do: function () {
            console.log('doing a');
        }
    };
    b.do();
    

    b、 js公司

    a = require('./a');
    module.exports = {
        do: function () {
            console.log('doing b');
        }
    };
    a.do();
    

    输出:

    node a.js
    b.js:7
    a.do();
        ^    
    TypeError: a.do is not a function
    
        7
  •  7
  •   Giuseppe Canale    7 年前

    您可以很容易地解决这个问题:只需在需要使用的模块中的任何其他内容之前导出数据模块.导出:

    A级.js

    class ClassA {
    
        constructor(){
            ClassB.someMethod();
            ClassB.anotherMethod();
        };
    
        static someMethod () {
            console.log( 'Class A Doing someMethod' );
        };
    
        static anotherMethod () {
            console.log( 'Class A Doing anotherMethod' );
        };
    
    };
    
    module.exports = ClassA;
    var ClassB = require( "./classB.js" );
    
    let classX = new ClassA();
    

    B.js类

    class ClassB {
    
        constructor(){
            ClassA.someMethod();
            ClassA.anotherMethod();
        };
    
        static someMethod () {
            console.log( 'Class B Doing someMethod' );
        };
    
        static anotherMethod () {
            console.log( 'Class A Doing anotherMethod' );
        };
    
    };
    
    module.exports = ClassB;
    var ClassA = require( "./classA.js" );
    
    let classX = new ClassB();
    
        8
  •  6
  •   zevero    8 年前

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

    当然,最好将所有require语句放在文件的顶部。但是在那里 在某些场合,我原谅自己从一个不相关的模块中挑选了一些东西。称之为黑客攻击,但有时这比引入进一步的依赖关系、添加额外的模块或添加新的结构(EventEmitter等)要好

        9
  •  6
  •   Bence Gedai    7 年前

    我见过的另一种方法是在第一行导出并将其保存为本地变量,如下所示:

    let self = module.exports = {};
    
    const a = require('./a');
    
    // Exporting the necessary functions
    self.func = function() { ... }
    

    我倾向于用这种方法,你知道它的缺点吗?

        10
  •  4
  •   Melik Karapetyan    6 年前

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

    文件“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语句将按预期工作。

        11
  •  4
  •   joeytwiddle    4 年前

    module.exports 对象,因为该对象可能已经在循环中给了其他模块!只需在里面指定属性 模块.导出 其他模块会看到它们出现。

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

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


    我觉得EC的回答更类似于以下的模式:

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

    这个 Object.assign() 将成员复制到 exports 对象,该对象已提供给其他模块。

    = 赋值在逻辑上是多余的,因为它只是设置 模块.导出 但我使用它是因为它有助于我的IDE(WebStorm)认识到这一点 firstMember

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

    reveal pattern ,因为您可以轻松地从对象中添加和删除导出,尤其是在使用ES6时 property shorthand .

    Object.assign(module.exports, {
        firstMember,
        //secondMember,
    });
    
        12
  •  2
  •   zevero    8 年前

    事实上,我最终需要依靠

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

        13
  •  1
  •   sagar saini    5 年前

    避免这种情况的一种方法是不需要另一个文件中的某个文件,只要将它作为参数传递给函数,就可以满足您在另一个文件中需要的任何内容。 这样就不会产生循环依赖。

        14
  •  0
  •   Tom    4 年前

    如果不能消除循环依赖关系(例如useraccount<-->userlogin),还有一个选项。。。

    就像使用 setTimeout()

    //useraccount.js
    
    let UserLogin = {};
    
    setTimeout(()=>UserLogin=require('./userlogin.js'), 10);
    
    class UserAccount{
     
    getLogin(){
    return new UserLogin(this.email);
    
    }
    
    }
    
    
    
    //userlogin.js
    
    let UserAccount ={};
    
    setTimeout(()=>UserAccount=require('./useraccount.js'), 15);
    
    
    class UserLogin{
    
    getUser(){
    
    return new User(this.token);
    
    }
    
    }