在节点JS中使用require()的范围问题

时间:2016-10-08 15:27:30

标签: node.js express scope requirejs require

我使用节点JS和Express模块​​设置了一个Web服务器。我的代码如下:

文件树:

/src
 |
 +-- server.js
 +-- /app
     |
     +-- routes.js

server.js

// set up ======================================================================
var express  = require('express');
var app      = express();
var mongoose = require('mongoose');

...

// configuration ===============================================================
mongoose.connect(configDB.url);

...

// routes ======================================================================
require('./app/routes.js')(app, passport);

// launch ======================================================================
app.listen(port);

routes.js

    module.exports = function(app, passport) {
        app.get('/some-route', function(req, res) {
            // this line bugs out
            var User = mongoose.model('User', userSchema);
        });
    };

我的问题:

routes.js 中调用 mongoose.model()会引发以下错误

  

ReferenceError:未定义mongoose

为什么我在这种情况下不知道mongoose是否包含在server.js中,包含routes.js的文件?我应该在routes.js中再次要求()mongoose吗?我在这里缺少什么?

2 个答案:

答案 0 :(得分:1)

模块中定义的变量仅对该模块是本地的。它们不属于您require()使用该模块的其他模块的范围。这就是你的路线模块不知道mongoose的原因。 require()操作不会将代码直接插入调用模块。相反,它从磁盘加载该代码,然后将其插入到自己的函数中并调用该函数。这为每个加载的模块提供了独立的范围。它未插入当前范围。

在这种情况下,您有几种选择:

    在路由中再次在mongoose模块中
  1. Require()。在可能的情况下,这通常是首选,因为这使得路由模块更加自给自足,并且在需要的东西中更容易重用。

  2. 传递您要与路径构造函数共享的对象,就像传入apppassport一样。当另一个模块所需的项目不仅仅是简单模块加载的结果时,此方法是首选方法。例如,app是调用构造函数的结果,因此另一个模块使用相同app实例的唯一方法是传递它。

  3. 您可以将路线呼叫到其他模块以请求信息。例如,由于您已经将app对象传递给路由,因此您可以将mongoose对象作为app对象上的属性,以便可以通过这种方式引用它或者您可以向app对象添加一个方法,以通过方法调用来检索它。

  4. 在这种情况下,由于mongoose只是一个缓存的模块,因此最好只将require()放入其中,但上述三种方法中的任何一种都可以正常工作。

答案 1 :(得分:1)

文件中包含的模块在另一个文件中不可见。在这里,您可以找到您创建的每个模块上可用的全局对象列表:

https://nodejs.org/api/globals.html

您在文件中定义的所有其他对象/变量,它们是在此文件的上下文中定义的。否则,这可能会产生巨大的问题,变量会覆盖其他文件中的其他变量并在项目中造成混乱。您可以将文件视为包含所有代码的函数,并且其中定义的所有内容都不可用于全局命名空间。

在您的情况下,您需要require('mongoose')所需的文件,并且它是这样构建的,以便维护与数据库的现有连接。