ChatGPT解决这个技术问题 Extra ChatGPT

在 Node.js 中的文件之间共享变量?

这里有2个文件:

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

// module.js
name = "foobar";

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

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

名称将在 main.js 中未定义。

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


j
jmar777

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

// 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...但就像我在原始答案中所说的那样,几乎永远不会一件好事。
为什么全局变量不好?如果我想将模块视为对象,是否有更好的方法来存储该对象的属性/属性?
F
Felipe Pereira

我找不到全局 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 不确定我是否能够仅使用提供的信息来回答您的评论,您可能想在网站中添加一个新问题
V
Vineeth Bhaskaran

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

//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
S
StefansArya

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

// 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();
    }
}

c
criz

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

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


这些片段是否矛盾? 1)“使用或不使用 var 关键字声明的变量已附加到全局对象。”和 2) “使用 var 关键字声明的变量对模块来说仍然是本地的。”
z
ztom

不是一种新方法,但有点优化。创建一个包含全局变量的文件并由 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

L
LCB

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

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

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

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