Делитесь переменными между файлами в Node.js?

126

Вот 2 файла:

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

// module.js
name = "foobar";

Когда у меня нет «вар», он работает. Но когда у меня есть:

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

имя будет неопределенным в main.js.

Я слышал, что глобальные переменные - это плохо, и вам лучше использовать "var" перед ссылками. Но разве в этом случае хороши глобальные переменные?

never_had_a_name
источник

Ответы:

184

Глобальные переменные почти никогда не приносят пользы (может быть, пару исключений ...). В этом случае, похоже, вы действительно просто хотите экспортировать свою переменную "name". Например,

// 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;
jmar777
источник
1
глобальные переменные - это плохо - я полностью согласен с этим. Но я мог бы сказать, что модуль имеет зависимость от переменной. Есть ли способ передать эту переменную в другой js-файл через функцию require?
appsthatmatter
1
@ jjoe64 Не уверен, что понимаю, что вы имеете в виду. Вы можете эффективно поделиться любой ценностью через exportsобъект.
jmar777
7
OP спрашивает, можно ли определить переменную в main.js, а затем использовать в module.js. У меня такое же требование определять пути, которые используются снова и снова.
designermonkey
4
@Designermonkey В этом случае вам, вероятно, лучше иметь объект конфигурации с теми типами значений, которые также могут быть require () 'd в данном файле. Обратите внимание, что вы можете просто сделать, global.foo = 'bar'а затем получить доступ в fooлюбом месте, где захотите ... но, как я сказал в своем первоначальном ответе, это почти никогда не бывает хорошо.
jmar777
Спасибо за это, я понял, как это сделать, и это работает. Спасибо за подтверждение, что у меня была правильная идея :)
designermonkey
37

Я не могу найти сценарий, в котором глобальный varвариант является лучшим вариантом, конечно, вы можете его иметь, но взгляните на эти примеры, и вы можете найти лучший способ добиться того же:

Сценарий 1. Поместите все в файлы конфигурации

Вам нужно какое-то значение, которое одинаково во всем приложении, но оно меняется в зависимости от среды (производственная, разработанная или тестовая), например, от типа почтовой программы, которые вам понадобятся:

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

и

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

(сделайте аналогичный конфиг и для разработчика)

Чтобы решить, какая конфигурация будет загружена, создайте основной файл конфигурации (он будет использоваться во всем приложении)

// 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 не уверен, смогу ли я ответить на ваш комментарий только предоставленной информацией, вы можете добавить новый вопрос на сайт
Фелипе Перейра
16

Если нам нужно поделиться несколькими переменными, используйте следующий формат

//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'
Винит Бхаскаран
источник
2
просто небольшое примечание, чтобы не упомянуть путаницу, которая может возникнуть на первом месте: модуль.exports - это то, что следует использовать! независимо от того, как называется ваш файл js (например, global.js). модуль - объект узла, существующий в глобальной области видимости! [поэтому в global.js мы используем module.exports = .....]
Мохамед Аллал
он будет успешным, если вы удалите 'let', и нет необходимости в «module.exports ..»
Ахмад Захаби
6

Сохраните любую переменную, к которой нужно предоставить общий доступ, как один объект. Затем передайте его загруженному модулю, чтобы он мог получить доступ к переменной через ссылку на объект.

// 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();
    }
}
StefansArya
источник
1

переменная, объявленная с ключевым словом var или без него, была привязана к глобальному объекту. Это основа для создания глобальных переменных в Node путем объявления переменных без ключевого слова var. Хотя переменные, объявленные с ключевым словом var, остаются локальными для модуля.

см. эту статью для дальнейшего понимания - https://www.hacksparrow.com/global-variables-in-node-js.html

Criz
источник
3
Эти фрагменты противоречат друг другу? 1) «переменная, объявленная с ключевым словом var или без него, была привязана к глобальному объекту». и 2) «переменные, объявленные с ключевым словом var, остаются локальными для модуля».
BaldEagle
1

С другим мнением, я думаю, что globalпеременные могут быть лучшим выбором, если вы собираетесь публиковать свой код npm, потому что вы не можете быть уверены, что все пакеты используют одну и ту же версию вашего кода. Поэтому, если вы используете файл для экспорта singletonобъекта, здесь возникнут проблемы.

Вы можете выбрать global, require.mainили любые другие объекты , которые являются общими для всех файлов.

Скажите, пожалуйста, есть ли какие-то лучшие решения.

LCB
источник