¿Compartir variables entre archivos en Node.js?

126

Aquí hay 2 archivos:

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

// module.js
name = "foobar";

Cuando no tengo "var" funciona. Pero cuando tengo:

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

el nombre estará indefinido en main.js.

He oído que las variables globales son malas y es mejor que uses "var" antes de las referencias. ¿Pero es este un caso donde las variables globales son buenas?

never_had_a_name
fuente

Respuestas:

184

Las variables globales casi nunca son algo bueno (tal vez una excepción o dos por ahí ...). En este caso, parece que realmente solo quieres exportar tu variable "nombre". P.ej,

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

Luego, en 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
fuente
1
las variables globales son malas, estoy totalmente de acuerdo con eso. Pero podría ser, que el módulo tiene una dependencia a una variable. ¿Hay alguna manera de pasar esta variable al otro archivo js a través de la función require?
appsthatmatter
1
@ jjoe64 No estoy seguro de seguir lo que quieres decir. Puede compartir efectivamente cualquier valor que desee a través del exportsobjeto.
jmar777
77
El OP pregunta si una variable puede definirse en main.js y luego usarse en module.js. Tengo el mismo requisito para definir rutas que se usan una y otra vez.
designermonkey
44
@Designermonkey En ese caso, probablemente sea mejor tener un objeto de configuración con esos tipos de valores que también se pueden requerir () 'd en un archivo determinado. Tenga en cuenta que simplemente puede hacer global.foo = 'bar'y luego acceder a foocualquier lugar que desee ... pero como dije en mi respuesta original, eso casi nunca es algo bueno.
jmar777
Gracias por eso, descubrí cómo hacerlo, y funciona de maravilla. Gracias por verificar que tuve la idea correcta :)
designermonkey
37

No puedo encontrar un escenario en el que un global varsea ​​la mejor opción, por supuesto que puede tener uno, pero eche un vistazo a estos ejemplos y puede encontrar una mejor manera de lograr lo mismo:

Escenario 1: poner las cosas en archivos de configuración

Necesita un valor que sea el mismo en toda la aplicación, pero cambia según el entorno (producción, desarrollo o prueba), el tipo de correo como ejemplo, necesitaría:

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

y

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

(hacer una configuración similar para dev también)

Para decidir qué configuración se cargará, cree un archivo de configuración principal (se usará en toda la aplicación)

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

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

Y ahora puede obtener los datos de esta manera:

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

Escenario 2: usar un archivo de constantes

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

Y úsalo de esta manera

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

Escenario 3: usar una función auxiliar para obtener / establecer los datos

No soy un gran admirador de este, pero al menos puedes rastrear el uso del 'nombre' (citando el ejemplo del OP) y poner las validaciones en su lugar.

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

Y úsalo

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

Podría haber un caso de uso cuando no hay otra solución que tener una global var, pero generalmente puede compartir los datos en su aplicación usando uno de estos escenarios, si está comenzando a usar node.js (como lo hice hace algún tiempo) intente para organizar la forma en que maneja los datos allí porque puede volverse desordenado realmente rápido.

Felipe Pereira
fuente
Me gustó el Escenario 2, pero ¿se pueden cambiar estos valores después de hablar de la compilación? como la mayoría de las veces, npm run build. ¿O conoce alguna forma de poder cambiar los valores después de la compilación?
Kashif Ullah
@KashifUllah no estoy seguro si puedo responder tu comentario solo con la información proporcionada, es posible que desees agregar una nueva pregunta en el sitio
Felipe Pereira
16

Si necesitamos compartir múltiples variables, use el siguiente formato

//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
fuente
2
solo una nota rápida para dejar de lado la confusión que puede surgir en el primer lugar: ¡module.exports es lo que debe usarse! como se llame su archivo js (ej .: global.js). ¡El módulo es un objeto de nodo que existe en el ámbito global! [así que dentro de global.js usamos module.exports = .....]
Mohamed Allal
tendrá éxito si elimina el 'let', y no hay necesidad de "module.exports .."
Ahmad Zahabi
6

Guarde cualquier variable que desee compartir como un solo objeto. Luego páselo al módulo cargado para que pueda acceder a la variable a través de la referencia de 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

En el otro archivo ...

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

una variable declarada con o sin la palabra clave var se adjuntó al objeto global. Esta es la base para crear variables globales en Node declarando variables sin la palabra clave var. Mientras que las variables declaradas con la palabra clave var permanecen locales para un módulo.

consulte este artículo para obtener más información: https://www.hacksparrow.com/global-variables-in-node-js.html

criz
fuente
3
¿Se contradicen estos fragmentos? 1) "una variable declarada con o sin la palabra clave var se adjuntó al objeto global". y 2) "las variables declaradas con la palabra clave var permanecen locales en un módulo".
BaldEagle
1

Con una opinión diferente, creo que las globalvariables podrían ser la mejor opción si va a publicar su código npm, porque no puede estar seguro de que todos los paquetes estén usando la misma versión de su código. Entonces, si usa un archivo para exportar un singletonobjeto, aquí causará problemas.

Puede elegir global, require.maino cualquier otro objeto que se comparta entre archivos.

Por favor, dime si hay algunas mejores soluciones.

LCB
fuente