глобальные переменные node.js?

208

Я спросил здесь: node.js требует наследования?

и мне сказали, что я могу установить переменные для глобальной области видимости, опуская переменную.

Это не работает для меня.

то есть:

_ = require('underscore');

Не делает _ доступным для необходимых файлов. Я могу установить с экспрессом app.setи иметь его в другом месте, хотя.

Может кто-нибудь подтвердить, что это должно работать? Спасибо.

Гарри
источник
Где у вас есть линия выше?
Ян Ханчич
3
Я думаю, что вы не должны начинать новый вопрос, если ответ на предыдущий вопрос не работает. Скорее добавьте туда комментарий и удалите принятый тег.
Чужой
5
Просто редактируя его, он появляется в списке активных вопросов.
МАК
3
Использование exports. Это намного лучше.
Эммерман
1
Может быть, это не работает, потому что у вас есть "использовать строгий"; в верхней части вашего файла. Это работает так для меня.
Геза Тури

Ответы:

237

Вы можете использовать globalтак:

global._ = require('underscore')
masylum
источник
28
Не могли бы вы предоставить немного больше информации, пожалуйста? Это часть JavaScript или часть узла? Это хороший шаблон для подражания? Как это сделать или использовать экспресс-набор? Спасибо
Гарри
4
Предыдущий комментарий неверен. В браузере windowэто глобальный объект. documentявляется собственностью window.
G-Wiz
77
Это НЕ хороший шаблон для подражания. Не делай этого. Соглашение об использовании 'require' для отделения модулей хорошо продумано. Вы не должны нарушать это без чертовски веской причины. Смотрите мой ответ ниже.
Дейв Допсон
Глобалов, как правило, следует избегать, но если вы действительно хотите их использовать. Все 3 приведенных ниже оператора эквивалентны и назначат переменную глобальной области видимости: GLOBAL._ = require ('underscore'); global._ = require ('underscore'); _ = требуется ('подчеркивание');
metaColin
Когда ваш проект станет немного больше, это станет настоящим кошмаром. Пожалуйста, взгляните на мой подход.
Оливер Диксон
219

В узле вы можете установить глобальные переменные через объект "global" или "GLOBAL":

GLOBAL._ = require('underscore'); // but you "shouldn't" do this! (see note below)

или полезнее ...

GLOBAL.window = GLOBAL;  // like in the browser

Из источника узла вы можете видеть, что они связаны друг с другом:

node-v0.6.6/src/node.js:
28:     global = this;
128:    global.GLOBAL = global;

В приведенном выше коде «это» является глобальным контекстом. В модульной системе commonJS (которую использует узел) объект «this» внутри модуля (т. Е. «Ваш код») НЕ является глобальным контекстом. Чтобы убедиться в этом, см. Ниже, где я извергаю объект «этот», а затем гигантский объект «ГЛОБАЛЬНЫЙ».

console.log("\nTHIS:");
console.log(this);
console.log("\nGLOBAL:");
console.log(global);

/* outputs ...

THIS:
{}

GLOBAL:
{ ArrayBuffer: [Function: ArrayBuffer],
  Int8Array: { [Function] BYTES_PER_ELEMENT: 1 },
  Uint8Array: { [Function] BYTES_PER_ELEMENT: 1 },
  Int16Array: { [Function] BYTES_PER_ELEMENT: 2 },
  Uint16Array: { [Function] BYTES_PER_ELEMENT: 2 },
  Int32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Uint32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Float32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Float64Array: { [Function] BYTES_PER_ELEMENT: 8 },
  DataView: [Function: DataView],
  global: [Circular],
  process: 
   { EventEmitter: [Function: EventEmitter],
     title: 'node',
     assert: [Function],
     version: 'v0.6.5',
     _tickCallback: [Function],
     moduleLoadList: 
      [ 'Binding evals',
        'Binding natives',
        'NativeModule events',
        'NativeModule buffer',
        'Binding buffer',
        'NativeModule assert',
        'NativeModule util',
        'NativeModule path',
        'NativeModule module',
        'NativeModule fs',
        'Binding fs',
        'Binding constants',
        'NativeModule stream',
        'NativeModule console',
        'Binding tty_wrap',
        'NativeModule tty',
        'NativeModule net',
        'NativeModule timers',
        'Binding timer_wrap',
        'NativeModule _linklist' ],
     versions: 
      { node: '0.6.5',
        v8: '3.6.6.11',
        ares: '1.7.5-DEV',
        uv: '0.6',
        openssl: '0.9.8n' },
     nextTick: [Function],
     stdout: [Getter],
     arch: 'x64',
     stderr: [Getter],
     platform: 'darwin',
     argv: [ 'node', '/workspace/zd/zgap/darwin-js/index.js' ],
     stdin: [Getter],
     env: 
      { TERM_PROGRAM: 'iTerm.app',
        'COM_GOOGLE_CHROME_FRAMEWORK_SERVICE_PROCESS/USERS/DDOPSON/LIBRARY/APPLICATION_SUPPORT/GOOGLE/CHROME_SOCKET': '/tmp/launch-nNl1vo/ServiceProcessSocket',
        TERM: 'xterm',
        SHELL: '/bin/bash',
        TMPDIR: '/var/folders/2h/2hQmtmXlFT4yVGtr5DBpdl9LAiQ/-Tmp-/',
        Apple_PubSub_Socket_Render: '/tmp/launch-9Ga0PT/Render',
        USER: 'ddopson',
        COMMAND_MODE: 'unix2003',
        SSH_AUTH_SOCK: '/tmp/launch-sD905b/Listeners',
        __CF_USER_TEXT_ENCODING: '0x12D732E7:0:0',
        PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/bin:/usr/X11/bin',
        PWD: '/workspace/zd/zgap/darwin-js',
        LANG: 'en_US.UTF-8',
        ITERM_PROFILE: 'Default',
        SHLVL: '1',
        COLORFGBG: '7;0',
        HOME: '/Users/ddopson',
        ITERM_SESSION_ID: 'w0t0p0',
        LOGNAME: 'ddopson',
        DISPLAY: '/tmp/launch-l9RQXI/org.x:0',
        OLDPWD: '/workspace/zd/zgap/darwin-js/external',
        _: './index.js' },
     openStdin: [Function],
     exit: [Function],
     pid: 10321,
     features: 
      { debug: false,
        uv: true,
        ipv6: true,
        tls_npn: false,
        tls_sni: true,
        tls: true },
     kill: [Function],
     execPath: '/usr/local/bin/node',
     addListener: [Function],
     _needTickCallback: [Function],
     on: [Function],
     removeListener: [Function],
     reallyExit: [Function],
     chdir: [Function],
     debug: [Function],
     error: [Function],
     cwd: [Function],
     watchFile: [Function],
     umask: [Function],
     getuid: [Function],
     unwatchFile: [Function],
     mixin: [Function],
     setuid: [Function],
     setgid: [Function],
     createChildProcess: [Function],
     getgid: [Function],
     inherits: [Function],
     _kill: [Function],
     _byteLength: [Function],
     mainModule: 
      { id: '.',
        exports: {},
        parent: null,
        filename: '/workspace/zd/zgap/darwin-js/index.js',
        loaded: false,
        exited: false,
        children: [],
        paths: [Object] },
     _debugProcess: [Function],
     dlopen: [Function],
     uptime: [Function],
     memoryUsage: [Function],
     uvCounters: [Function],
     binding: [Function] },
  GLOBAL: [Circular],
  root: [Circular],
  Buffer: 
   { [Function: Buffer]
     poolSize: 8192,
     isBuffer: [Function: isBuffer],
     byteLength: [Function],
     _charsWritten: 8 },
  setTimeout: [Function],
  setInterval: [Function],
  clearTimeout: [Function],
  clearInterval: [Function],
  console: [Getter],
  window: [Circular],
  navigator: {} }
*/

** Примечание: в отношении настройки "GLOBAL._", в общем, вы должны просто сделать var _ = require('underscore');. Да, вы делаете это в каждом отдельном файле с подчеркиванием, как в Java import com.foo.bar;. Это облегчает понимание того, что делает ваш код, потому что связи между файлами являются «явными». Слегка раздражает, но это хорошо. .... Это проповедь.

Из каждого правила есть исключение. У меня был точно ровно один экземпляр, где мне нужно было установить «GLOBAL._». Я создавал систему для определения «конфигурационных» файлов, которые были в основном JSON, но были «написаны на JS» для большей гибкости. Такие конфигурационные файлы не имели операторов 'require', но я хотел, чтобы у них был доступ к подчеркиванию (система ENTIRE была основана на шаблонах подчеркивания и подчеркивания), поэтому перед оценкой "config" я бы установил "GLOBAL._". Так что да, для каждого правила есть где-то исключение. Но вам лучше иметь чертову вескую причину, а не просто «я устал набирать« требовать », поэтому я хочу порвать с соглашением».

Дейв Допсон
источник
7
Каковы недостатки использования GLOBAL? Зачем мне чертовски веская причина? Суть в том, что мое приложение работает, верно?
trusktr
26
в конечном счете, да, если вы отправляете, это все, что имеет значение. Тем не менее, определенные практики известны как «лучшие практики», и следование им, как правило, увеличивает ваши шансы на доставку и / или способность поддерживать то, что вы создали. Важность следования «хорошей практике» возрастает с увеличением размера проекта и его долговечности. Я встроил все виды неприятных взломов в недолговечные проекты, которые были написаны один раз, никогда не читаются (и «один разработчик»). В более крупном проекте подобная угловая обработка в конечном итоге будет стоить вам импульса проекта.
Дейв Допсон,
48
В частности, с GLOBAL проблема заключается в удобочитаемости. Если ваша программа беспорядочно использует глобальные переменные, это означает, что для понимания кода я должен понимать динамическое состояние выполнения всего приложения. Вот почему программисты с подозрением относятся к глобальным. Я уверен, что есть десятки способов их эффективного использования, но мы, как правило, только что видели, как юные программисты злоупотребляли ими из-за плохой работы продукта.
Дейв Допсон
2
Почему вы не можете просто поместить свои конфиги в обычный .jsфайл и позвонить requireперед экспортом конфигов?
Азат
4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern . если то, что вы делаете, соответствует шаблону Singleton, тогда это может иметь смысл. Соединения с БД могут быть одиночными, когда: 1) установка дорогостоящая, 2) вы хотите, чтобы соединение устанавливалось только один раз, 3) объект соединения является долгоживущим и не переходит в состояние отказа в случае сбоя сети, 4) объект соединения является поточно-ориентированным / может использоваться многими разными абонентами.
Дейв Допсон
78

Другие решения, использующие ключевое слово GLOBAL, - это кошмар для поддержания / читабельности (+ загрязнение пространства имен и ошибки), когда проект становится больше. Я видел эту ошибку много раз, и мне было трудно ее исправить.

Используйте файл JS, затем используйте экспорт модуля.

Пример:

globals.js

var Globals = {
    'domain':'www.MrGlobal.com';
}

module.exports = Globals;

Тогда, если вы хотите использовать их, используйте требуют.

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.
Оливер Диксон
источник
13
Я, конечно, не люблю единорогов, но мне нравится ваш подход. Спасибо.
Джонатас Уокер
А как насчет изменения globals.domainхотя?
Fizzix
1
@iLoveUnicorns спасибо за ответ. Я рассмотрю альтернативы, такие как «экспресс-сессия», так как она мне в основном нужна для хранения зарегистрированных пользовательских данных.
Fizzix
11
Хотя это, на мой взгляд, лучший подход, он не создает глобальных параметров и не отвечает на заданный вопрос. Это альтернативный подход, и я бы всегда поощрял его, однако явная бычья дерзость таких заявлений, как «Это единственный правильный ответ в этой теме», просто здесь не подходит. stackoverflow.com/help/be-nice
Thor84no
2
Это может быть лучшим подходом, но если вы пытаетесь запускать скрипты с внешним автором, которые полагаются на что-то, находящееся в глобальном пространстве имен, это вам не поможет. IOW, это не отвечает на вопрос.
Бинки
12

Как насчет глобального пространства имен, как global.MYAPI = {}

global.MYAPI._ = require('underscore')

Отредактируйте после комментария Камило-Мартина : Все другие постеры говорят о плохой схеме. Таким образом, оставляя это обсуждение в стороне, лучший способ определения глобальной переменной (вопрос OP) - через пространства имен.

@tip: http://thanpol.as/javascript/development-using-namespaces

Игорь Парра
источник
3
Вот для чего require! Можно использовать пространства имен, но не использовать все global.foo = global.foo || {}файлы или что-то в этом роде. Требуется файл, который определяет пространство имен. Сделай это для детей.
Камило Мартин
@ camilo-martin Привет, 1) Определяя global.MYAPI._ вам не нужно определять его во всех файлах, вот почему это глобально. 2) Это не должно быть с детьми. Даже если все говорят, что это плохая модель, это зависит от программиста и данной ситуации, как он использует эту возможность языка.
Игорь Парра
2
Да, но допустим, вы объявляете некоторые функциональные возможности пространства имен в отдельном файле. Затем вам нужен файл для использования объекта, который обратный и идет вразрез с CommonJS и CommonSense, тоже. Если вы собираетесь что-то требовать, пусть пользовательский код требует пространства имен и не требуется для пространства имен. Заметьте, я не говорю ничего против пространств имен, просто есть соглашения о том, кто звонит кому по какой-то причине. А на стороне клиента у вас нет того, что имеет узел; Посмотрите, что ссылка, которую вы упоминаете, делает что-то определенным образом (через глобальный канал), потому что это касается браузера, а не узла.
Камило Мартин
1
Грустно URL вы вывесили только работает , если вы выходите из слэш;)
дирижабль
10

Вы можете просто использовать глобальный объект.

var X = ['a', 'b', 'c'];
global.x = X;

console.log(x);
//['a', 'b', 'c']
Жоао Фалькао
источник
5

Я согласен с тем, что использование глобального пространства имен GLOBAL для установки чего-либо глобального является плохой практикой, и я не использую его вообще в теории ( теоретически это рабочее слово). Однако (да, действующий) я использую его для установки пользовательских классов ошибок:

// Some global/config file that gets called in initialisation

global.MyError = [Function of MyError];

Да, здесь табу, но если ваш сайт / проект использует пользовательские ошибки повсеместно, вам, в основном, нужно определить его везде или, по крайней мере, где-то:

  1. Определите класс ошибок в первую очередь
  2. В сценарии, где вы бросаете его
  3. В сценарии, где вы ловите это

Определение моих пользовательских ошибок в глобальном пространстве имен избавляет меня от необходимости требовать библиотеки пользовательских ошибок. Imaging выбрасывает пользовательскую ошибку, где эта пользовательская ошибка не определена.

Также, если это не так, пожалуйста, дайте мне знать, так как я только начал делать это недавно

DrunkenBeetle
источник