【问题标题】:Share variables between files in Node.js?在 Node.js 中的文件之间共享变量?
【发布时间】:2011-04-24 19:01:17
【问题描述】:

这里有 2 个文件:

// main.js
require('./modules');
console.log(name); // prints "foobar"

// module.js
name = "foobar";

当我没有“var”时,它可以工作。但是当我有:

// module.js
var name = "foobar";

name 将在 main.js 中未定义。

我听说全局变量不好,你最好在引用之前使用“var”。但是这是全局变量好的情况吗?

【问题讨论】:

    标签: javascript node.js global-variables


    【解决方案1】:

    全局变量几乎从来都不是一件好事(可能有一两个例外......)。在这种情况下,看起来您真的只想导出“名称”变量。例如,

    // module.js
    var name = "foobar";
    // export it
    exports.name = name;
    

    然后,在 main.js...

    //main.js
    // get a reference to your required module
    var myModule = require('./module');
    
    // name is a member of myModule due to the export above
    var name = myModule.name;
    

    【讨论】:

    • 全局变量不好——我完全同意这一点。但我可能是,该模块依赖于一个变量。有没有办法通过 require 函数将此变量传递给另一个 js 文件?
    • @jjoe64 不确定我是否理解您的意思。您可以通过exports 对象有效地分享您想要的任何价值。
    • OP在询问是否可以在main.js中定义一个变量,然后在module.js中使用。我对定义反复使用的路径有同样的要求。
    • @Designermonkey 在这种情况下,您最好拥有一个配置对象,该对象具有也可以被 require() 放入给定文件中的那些类型的值。请注意,您可以只需执行global.foo = 'bar',然后在您想要的任何地方访问foo...但就像我在原始答案中所说的那样,几乎永远不会一件好事。
    • 谢谢你,我想出了如何做到这一点,它很有效。感谢您验证我的想法是正确的 :)
    【解决方案2】:

    我找不到全局 var 是最佳选择的方案,当然您可以有一个,但是看看这些示例,您可能会找到更好的方法来完成同样的事情:

    场景 1:将内容放入配置文件

    您需要一些在整个应用程序中相同的值,但它会根据环境(生产、开发或测试)而变化,例如邮件类型,您需要:

    // File: config/environments/production.json
    {
        "mailerType": "SMTP",
        "mailerConfig": {
          "service": "Gmail",
          ....
    }
    

    // File: config/environments/test.json
    {
        "mailerType": "Stub",
        "mailerConfig": {
          "error": false
        }
    }
    

    (也为 dev 做一个类似的配置)

    要决定加载哪个配置,请创建一个主配置文件(这将在整个应用程序中使用)

    // File: config/config.js
    var _ = require('underscore');
    
    module.exports = _.extend(
        require(__dirname + '/../config/environments/' + process.env.NODE_ENV + '.json') || {});
    

    现在您可以像这样获取数据

    // File: server.js
    ...
    var config = require('./config/config');
    ...
    mailer.setTransport(nodemailer.createTransport(config.mailerType, config.mailerConfig));
    

    场景 2:使用常量文件

    // File: constants.js
    module.exports = {
      appName: 'My neat app',
      currentAPIVersion: 3
    };
    

    并以这种方式使用它

    // File: config/routes.js
    
    var constants = require('../constants');
    
    module.exports = function(app, passport, auth) {
      var apiroot = '/api/v' + constants.currentAPIVersion;
    ...
      app.post(apiroot + '/users', users.create);
    ...
    

    场景 3:使用辅助函数获取/设置数据

    不是这个的忠实粉丝,但至少您可以跟踪“名称”的使用(引用 OP 的示例)并进行验证。

    // File: helpers/nameHelper.js
    
    var _name = 'I shall not be null'
    
    exports.getName = function() {
      return _name;
    };
    
    exports.setName = function(name) {
      //validate the name...
      _name = name;
    };
    

    并使用它

    // File: controllers/users.js
    
    var nameHelper = require('../helpers/nameHelper.js');
    
    exports.create = function(req, res, next) {
      var user = new User();
      user.name = req.body.name || nameHelper.getName();
      ...
    

    可能存在一个用例,即除了拥有全局 var 之外没有其他解决方案,但如果您开始使用 node.js(如我是前段时间)尝试组织你在那里处理数据的方式,因为它很快就会变得混乱。

    【讨论】:

    • 我喜欢场景2,但是在我们讨论构建之后可以更改这些值吗?就像我们经常做的那样,npm run build。或者你知道一些在构建后能够改变值的方法吗?
    • @KashifUllah 不确定我是否能够仅使用提供的信息来回答您的评论,您可能想在网站中添加一个新问题
    【解决方案3】:

    如果我们需要共享多个变量,请使用以下格式

    //module.js
       let name='foobar';
       let city='xyz';
       let company='companyName';
    
       module.exports={
        name,
        city,
        company
      }
    

    用法

      // main.js
        require('./modules');
        console.log(name); // print 'foobar'
    

    【讨论】:

    • 只是一个简短的说明,以排除一开始可能出现的混淆:module.exports 是应该使用的!无论您调用什么 js 文件(例如:global.js)。 module 是一个存在于全局范围内的节点对象! [所以在 global.js 中我们使用 module.exports=.....]
    • 去掉'let'就成功了,不需要"module.exports.."
    • 有没有办法在所有导入它的文件中更新来自module.js 的值(例如名称、城市、公司),以便所有导入它的文件都可以访问更新的值?是否有类似“动态全局变量”的东西可以被任何引用它的模块访问和编辑?我有a question with more context here
    【解决方案4】:

    将任何想要共享的变量保存为一个对象。然后将其传递给加载的模块,以便它可以通过对象引用访问变量..

    // main.js
    var myModule = require('./module.js');
    var shares = {value:123};
    
    // Initialize module and pass the shareable object
    myModule.init(shares);
    
    // The value was changed from init2 on the other file
    console.log(shares.value); // 789
    

    在另一个文件上..

    // module.js
    var shared = null;
    
    function init2(){
        console.log(shared.value); // 123
        shared.value = 789;
    }
    
    module.exports = {
        init:function(obj){
            // Save the shared object on current module
            shared = obj;
    
            // Call something outside
            init2();
        }
    }
    

    【讨论】:

      【解决方案5】:

      使用或不使用 var 关键字声明的变量已附加到全局对象。这是在 Node 中通过声明不带 var 关键字的变量来创建全局变量的基础。虽然使用 var 关键字声明的变量仍然是模块的本地变量。

      看这篇文章进一步了解-https://www.hacksparrow.com/global-variables-in-node-js.html

      【讨论】:

      • 这些片段是否矛盾? 1)“使用或不使用 var 关键字声明的变量已附加到全局对象。”和 2) “使用 var 关键字声明的变量仍然是模块的本地变量。”
      【解决方案6】:

      如果您打算将代码发布到npm,我认为global 变量可能是最好的选择,因为您不能确定所有包都使用相同的代码版本。因此,如果您使用文件导出singleton 对象,则会在此处引起问题。

      您可以选择globalrequire.main 或任何其他跨文件共享的对象。

      否则,将您的包安装为可选依赖包可以避免此问题。

      请告诉我是否有更好的解决方案。

      【讨论】:

        【解决方案7】:

        不是一种新方法,但经过了一些优化。创建一个包含全局变量的文件,并通过exportrequire 共享它们。在此示例中,Getter 和 Setter 更具动态性,全局变量可以是只读的。要定义更多全局变量,只需将它们添加到 globals 对象即可。

        global.js

        const globals = {
          myGlobal: {
            value: 'can be anytype: String, Array, Object, ...'
          },
          aReadonlyGlobal: {
            value: 'this value is readonly',
            protected: true
          },
          dbConnection: {
            value: 'mongoClient.db("database")'
          },
          myHelperFunction: {
            value: function() { console.log('do help') }
          },
        }
        
        exports.get = function(global) {
          // return variable or false if not exists
          return globals[global] && globals[global].value ? globals[global].value : false;
        };
        
        exports.set = function(global, value) {
          // exists and is protected: return false
          if (globals[global] && globals[global].protected && globals[global].protected === true)
            return false;
          // set global and return true
          globals[global] = { value: value };
          return true;
        };
        

        在 any-other-file.js 中获取和设置的示例

        const globals = require('./globals');
        
        console.log(globals.get('myGlobal'));
        // output: can be anytype: String, Array, Object, ...
        
        globals.get('myHelperFunction')();
        // output: do help
        
        let myHelperFunction = globals.get('myHelperFunction');
        myHelperFunction();
        // output: do help
        
        console.log(globals.set('myGlobal', 'my new value'));
        // output: true
        console.log(globals.get('myGlobal'));
        // output: my new value
        
        console.log(globals.set('aReadonlyGlobal', 'this shall not work'));
        // output: false
        console.log(globals.get('aReadonlyGlobal'));
        // output: this value is readonly
        
        console.log(globals.get('notExistingGlobal'));
        // output: false
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-08-14
          • 1970-01-01
          • 1970-01-01
          • 2015-09-21
          • 2015-08-08
          • 1970-01-01
          相关资源
          最近更新 更多