Partager des variables entre des fichiers dans Node.js?

126

Voici 2 fichiers:

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

// module.js
name = "foobar";

Quand je n'ai pas "var", ça marche. Mais quand j'ai:

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

Le nom ne sera pas défini dans main.js.

J'ai entendu dire que les variables globales sont mauvaises et il vaut mieux utiliser "var" avant les références. Mais est-ce un cas où les variables globales sont bonnes?

never_had_a_name
la source

Réponses:

184

Les variables globales ne sont presque jamais une bonne chose (peut-être une exception ou deux là-bas ...). Dans ce cas, il semble que vous souhaitiez simplement exporter votre variable "nom". Par exemple,

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

Ensuite, dans 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
la source
1
les variables globales sont mauvaises - je suis totalement d'accord avec cela. Mais je pourrais être, que le module a une dépendance à une variable. Existe-t-il un moyen de passer cette variable à l'autre fichier js via la fonction require?
appsthatmatter
1
@ jjoe64 Je ne suis pas sûr de comprendre ce que vous voulez dire. Vous pouvez effectivement partager n'importe quelle valeur que vous souhaitez via l' exportsobjet.
jmar777
7
L'OP demande si une variable peut être définie dans le main.js, puis utilisée dans module.js. J'ai la même exigence pour définir des chemins qui sont utilisés encore et encore.
designermonkey
4
@Designermonkey Dans ce cas, il vaut probablement mieux avoir un objet de configuration avec ces types de valeurs qui peuvent également être require () 'd dans un fichier donné. Notez que vous pouvez simplement faire global.foo = 'bar'et accéder à foon'importe quel endroit de votre choix ... mais comme je l'ai dit dans ma réponse initiale, ce n'est presque jamais une bonne chose.
jmar777
Merci pour cela, j'ai compris comment faire cela, et cela fonctionne un régal. Merci d'avoir vérifié que j'avais la bonne idée :)
designermonkey
37

Je ne parviens pas à trouver un scénario où un global varest la meilleure option, bien sûr vous pouvez en avoir un, mais jetez un œil à ces exemples et vous trouverez peut-être un meilleur moyen d'accomplir la même chose:

Scénario 1: mettre les choses dans les fichiers de configuration

Vous avez besoin d'une valeur identique dans toute l'application, mais cela change en fonction de l'environnement (production, développement ou test), le type de courrier par exemple, dont vous auriez besoin:

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

et

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

(faire une configuration similaire pour les développeurs aussi)

Pour décider quelle configuration sera chargée, créez un fichier de configuration principal (il sera utilisé dans toute l'application)

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

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

Et maintenant, vous pouvez obtenir les données comme ceci:

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

Scénario 2: utiliser un fichier de constantes

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

Et utilisez-le de cette façon

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

Scénario 3: utiliser une fonction d'assistance pour obtenir / définir les données

Pas un grand fan de celui-ci, mais au moins vous pouvez suivre l'utilisation du 'nom' (en citant l'exemple de l'OP) et mettre en place des validations.

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

Et utilisez-le

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

Il pourrait y avoir un cas d'utilisation où il n'y a pas d'autre solution que d'avoir un global var, mais généralement vous pouvez partager les données dans votre application en utilisant l'un de ces scénarios, si vous commencez à utiliser node.js (comme je l'étais il y a quelque temps) essayez pour organiser la façon dont vous gérez les données là-bas, car cela peut devenir très rapidement compliqué.

Felipe Pereira
la source
J'ai aimé le scénario 2, mais ces valeurs peuvent-elles être modifiées après avoir parlé de build? comme le plus souvent nous le faisons, npm run build. Ou connaissez-vous un moyen de changer les valeurs après la construction?
Kashif Ullah
@KashifUllah Je ne sais pas si je suis en mesure de répondre à votre commentaire uniquement avec les informations fournies, vous pouvez ajouter une nouvelle question sur le site
Felipe Pereira
16

Si nous devons partager plusieurs variables, utilisez le format ci-dessous

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

   module.exports={
    name,
    city,
    company
  }

Usage

  // main.js
    require('./modules');
    console.log(name); // print 'foobar'
Vineeth Bhaskaran
la source
2
juste une petite note pour laisser de côté la confusion qui peut survenir au premier abord: module.exports est ce qu'il faut utiliser! quel que soit le nom de votre fichier js (ex: global.js). module est un objet nœud existant dans la portée globale! [donc dans global.js nous utilisons module.exports = .....]
Mohamed Allal
il réussira si vous supprimez le 'let', et il n'y a pas besoin de "module.exports .."
Ahmad Zahabi
6

Enregistrez toute variable à partager comme un seul objet. Puis passez-le au module chargé pour qu'il puisse accéder à la variable via la référence d'objet.

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

Sur l'autre dossier ..

// 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
la source
1

une variable déclarée avec ou sans le mot-clé var est attachée à l'objet global. C'est la base pour créer des variables globales dans Node en déclarant des variables sans le mot clé var. Alors que les variables déclarées avec le mot-clé var restent locales à un module.

voir cet article pour plus de compréhension - https://www.hacksparrow.com/global-variables-in-node-js.html

criz
la source
3
Ces fragments se contredisent-ils? 1) "une variable déclarée avec ou sans le mot-clé var a été attachée à l'objet global." et 2) "les variables déclarées avec le mot-clé var restent locales à un module."
BaldEagle
1

Avec un avis différent, je pense que les globalvariables pourraient être le meilleur choix si vous allez publier votre code npm, car vous ne pouvez pas être sûr que tous les packages utilisent la même version de votre code. Donc, si vous utilisez un fichier pour exporter un singletonobjet, cela causera des problèmes ici.

Vous pouvez choisir global, require.mainou tout autre objet qui est partagé entre les fichiers.

Veuillez me dire s'il existe de meilleures solutions.

LCB
la source