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

Scoping issue using require() in node JS

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

文件树:

/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 is not defined

当我将 mongoose 包含在包含 routes.js 的文件 server.js 中时,为什么在此上下文中不为人所知?我应该在 routes.js 中再次要求()猫鼬吗?我在这里错过了什么?

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

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

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

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

  3. 您可以让路由调用其他模块以请求信息。例如,由于您已经将 app 对象传递给路由,您可以将 mongoose 对象作为 属性 放在 app 对象上,以便可以引用它这样或者您可以向 app 对象添加一个方法以通过方法调用检索它。

在这种情况下,由于 mongoose 只是一个缓存模块,因此再次 require() 可能最有意义,但上述三种方法中的任何一种都可以。

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

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

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

在你的情况下,你必须 require('mongoose') 在你需要的文件中,它是这样构建的,以便可以保持与数据库的现有连接。