Compartilhar variáveis ​​entre arquivos no Node.js?

126

Aqui estão 2 arquivos:

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

// module.js
name = "foobar";

Quando não tenho "var", funciona. Mas quando eu tenho:

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

O nome será indefinido em main.js.

Ouvi dizer que variáveis ​​globais são ruins e é melhor você usar "var" antes das referências. Mas é este o caso em que variáveis ​​globais são boas?

never_had_a_name
fonte

Respostas:

184

Variáveis ​​globais quase nunca são uma coisa boa (talvez uma exceção ou duas por aí ...). Nesse caso, parece que você realmente deseja apenas exportar sua variável "name". Por exemplo,

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

Então, em 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;
jmar777
fonte
1
variáveis ​​globais são ruins - eu concordo totalmente com isso. Mas eu poderia estar, que o módulo depende de uma variável. Existe uma maneira de passar essa variável para o outro arquivo js através da função require?
appsthatmatter 23/06
1
@ jjoe64 Não sei se entendi o que você quer dizer. Você pode compartilhar efetivamente qualquer valor que desejar através do exportsobjeto.
jmar777
7
O OP está perguntando se uma variável pode ser definida no main.js e depois usada no module.js. Eu tenho o mesmo requisito para definir caminhos que são usados ​​repetidamente.
Designer-
4
@Designermonkey Nesse caso, provavelmente é melhor ter um objeto de configuração com esses tipos de valores que também podem ser requeridos () em um determinado arquivo. Observe que você pode fazer global.foo = 'bar'e acessar em fooqualquer lugar que desejar ... mas como eu disse na minha resposta original, isso quase nunca é uma coisa boa.
Jmar777 # 13/14
Obrigado por isso, eu descobri como fazer isso e funciona. Obrigado por verificar que teve a idéia certa :)
designermonkey
37

Não consigo encontrar um cenário em que uma global varseja a melhor opção, é claro que você pode ter uma, mas dê uma olhada nesses exemplos e poderá encontrar uma maneira melhor de realizar o mesmo:

Cenário 1: Coloque as coisas nos arquivos de configuração

Você precisa de algum valor que seja o mesmo no aplicativo, mas ele muda dependendo do ambiente (produção, desenvolvimento ou teste), do tipo de mala direta como exemplo, você precisa:

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

e

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

(faça uma configuração semelhante para dev também)

Para decidir qual configuração será carregada, crie um arquivo de configuração principal (isso será usado em todo o aplicativo)

// File: config/config.js
var _ = require('underscore');

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

E agora você pode obter dados como este:

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

Cenário 2: Use um arquivo de constantes

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

E use desta maneira

// 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);
...

Cenário 3: Use uma função auxiliar para obter / definir os dados

Não é um grande fã deste, mas pelo menos você pode acompanhar o uso do 'nome' (citando o exemplo do OP) e colocar as validações em vigor.

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

E use

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

Pode haver um caso de uso em que não há outra solução além de ter uma global var, mas geralmente você pode compartilhar os dados em seu aplicativo usando um desses cenários, se estiver começando a usar o node.js (como eu estava há algum tempo), tente para organizar a maneira como você lida com os dados por lá, porque eles podem ficar confusos muito rápido.

Felipe Pereira
fonte
Gostei do Cenário 2, mas esses valores podem ser alterados depois de conversarmos sobre construção? como costumamos fazer, o npm executa build. Ou você conhece alguma maneira de poder alterar valores após a compilação?
Kashif Ullah
@KashifUllah não tenho certeza se eu sou capaz de responder o seu comentário apenas com as informações fornecidas, você pode querer adicionar uma nova pergunta no site
Felipe Pereira
16

Se precisarmos compartilhar várias variáveis, use o formato abaixo

//module.js
   let name='foobar';
   let city='xyz';
   let company='companyName';

   module.exports={
    name,
    city,
    company
  }

Uso

  // main.js
    require('./modules');
    console.log(name); // print 'foobar'
Vineeth Bhaskaran
fonte
2
apenas uma nota rápida para deixar de fora a confusão que pode surgir no primeiro ponto: module.exports é o que deve ser usado! seja qual for o nome do seu arquivo js (ex: global.js). O módulo é um objeto de nó que existe no escopo global! [lo dentro global.js usamos module.exports = .....]
Mohamed Allal
será bem-sucedido se você remover o 'let' e não for necessário o "module.exports .."
Ahmad Zahabi 5/11/19
6

Salve qualquer variável que queira ser compartilhada como um objeto. Depois, passe-o para o módulo carregado para que ele possa acessar a variável através da referência a objeto.

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

No outro arquivo ..

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

uma variável declarada com ou sem a palavra-chave var foi anexada ao objeto global. Essa é a base para a criação de variáveis ​​globais no Node, declarando variáveis ​​sem a palavra-chave var. Enquanto as variáveis ​​declaradas com a palavra-chave var permanecem locais em um módulo.

consulte este artigo para obter mais informações - https://www.hacksparrow.com/global-variables-in-node-js.html

Criz
fonte
3
Esses fragmentos contradizem? 1) "uma variável declarada com ou sem a palavra-chave var foi anexada ao objeto global." e 2) "variáveis ​​declaradas com a palavra-chave var permanecem locais em um módulo".
precisa saber é o seguinte
1

Com uma opinião diferente, acho que as globalvariáveis ​​podem ser a melhor opção se você deseja publicar seu código npm, porque você não pode ter certeza de que todos os pacotes estão usando a mesma versão do seu código. Portanto, se você usar um arquivo para exportar um singletonobjeto, ele causará problemas aqui.

Você pode escolher global, require.mainou quaisquer outros objetos que são compartilhados entre arquivos.

Por favor, diga-me se existem algumas soluções melhores.

LCB
fonte