将参数传递给 require (加载模块时)

142

使用require加载模块时,是否可以传递参数?

我有一个名为login.js的模块,它提供了登录功能。它需要数据库连接,并且我希望所有模块都使用相同的数据库连接。现在我导出一个函数login.setDatabase(...),可以让我指定数据库连接,这个方法可以正常工作。但我更希望在加载模块时就传递数据库和其他必要的参数。

var db = ...
var login = require("./login.js")(db);

我对NodeJS还很陌生,通常使用Java和Spring Framework进行开发,所以是的...这是一个构造函数注入 :) 是否有可能做出我上面提供的代码?


我还建议查看这个问题的答案。正如我在我的回答中指出的那样,一种常见的习惯是将app对象传递给所需的模块。 - David Weldon
不要为了db而进行所有这些参数传递,你可以使用singleton实现,在需要的地方调用db.getInstance()。 - wulfgarpro
在你的导出文件中,将“db”用作函数的参数。 - mercury
3个回答

255

根据您在此答案中的评论,我会这样做:

module.exports = function (app, db) {
    var module = {};

    module.auth = function (req, res) {
        // This will be available 'outside'.
        // Authy stuff that can be used outside...
    };

    // Other stuff...
    module.pickle = function(cucumber, herbs, vinegar) {
        // This will be available 'outside'.
        // Pickling stuff...
    };

    function jarThemPickles(pickle, jar) {
        // This will be NOT available 'outside'.
        // Pickling stuff...

        return pickleJar;
    };

    return module;
};

我几乎所有的模块都是按照这种方式构建的。看起来对我很有效。


“app”参数是否必要或者我可以省略它?我的模块不会明确使用该“app”参数,但我不知道它是否对Node.js的某些内部事务是必需的。如果可以省略的话,我的模块声明将如下所示:module.exports = function (db) { - Ulysses Alves
1
那是特定于 Express 应用程序的,所以绝对不必要。 - floatingLomas
1
那么如果您多次引用该模块会发生什么?第一个 require(mymodule)(myargs) 将为您提供一个可用的模块。但是,如果您在另一个模块中从其他地方引用它呢?在基本系统中似乎涉及到缓存,但在这个系统中,缓存将在后续调用 require() 时返回裸发生器方法,并且如果您传递参数给 require()(someargs),则会返回不同的模块...也许我漏掉了什么。 - Tom
2
@TomH 如果是这样的话,你需要进行缓存。为此,你需要在导出函数之外设置 var module;,然后当你进入时,你需要检查 module 是否已经定义,如果是,则返回它(如果没有,则初始化它)。这样说清楚了吗? - floatingLomas
@floatingLomas:你的意思是像这样var instances = {}; module.exports = name => instances[name] ? instances[name] : instances[name] = name + ": " + Math.floor(Math.random() * 10000);如果你使用相同的参数多次需要该模块,你将得到一个单一的实例。 - Nicolas Le Thierry d'Ennequin
显示剩余3条评论

52

我不确定这对人们是否仍然有用,但是使用ES6,我找到了一种我认为干净实用的方法。

class MyClass { 
  constructor ( arg1, arg2, arg3 )
  myFunction1 () {...}
  myFunction2 () {...}
  myFunction3 () {...}
}

module.exports = ( arg1, arg2, arg3 ) => { return new MyClass( arg1,arg2,arg3 ) }

然后您就会得到期望的行为。

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )

1
使用ES6的import语句(而不是require语句),这个功能会如何工作? - Brendon S

34

可以的。在你的login模块中,只需导出一个接受db作为其参数的单个函数即可。例如:

是的。在您的login模块中,只需导出一个以db为参数的单个函数。例如:

module.exports = function(db) {
  ...
};

1
我试过了。在login.js中`module.exports = function(app,db) { ... }module.exports.auth = function(req,res) { ... authentication stuff }`它确实调用了“匿名”函数并设置了appdb变量,但是当我这样做时,我的应用程序将无法找到auth函数。我做错了什么?如果我删除匿名函数,则可以再次访问auth函数。 - Andreas Selenwall
1
就像 JavaScript 中的所有内容一样,exports 是一个对象。您可以向其分配属性(多个导出项),也可以将其分配给一个值。听起来您将 exports 分配给了一个函数,但是然后将 auth 分配为您分配给 exports 的函数的属性。因此,您需要执行 var auth = require("./login.js").auth,这可能不是您想要的。如果您想使用原始问题中的模式,则最好坚持单个导出值。如果仍然不清楚,请建议您发布一个 gist 给我查看。 - David Weldon
1
再次阅读后,听起来你可能已经将auth分配为exports对象的属性,然后在模块中稍后将exports分配给一个函数(从而覆盖了先前的分配)。如果你颠倒分配的顺序,你应该能够像预期的那样访问auth函数。再次强调,没有实际看到代码很难确定。 - David Weldon
1
非常感谢您的帮助。我之前没有意识到您使用 require('login').auth 的目的。我以为在 var login = require('login')var login = require('login')(app) 中没有区别,但实际上它们之间有很大的区别。匿名函数返回的并不是魔法,而是另一个函数/对象。现在,匿名函数不再具有 module.exports.auth,而是返回了 auth 函数(以及其他函数),即 return { auth: authFunction, login: loginFunction}。所以现在它可以正常工作了。谢谢。 - Andreas Selenwall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接