глобальні змінні node.js?


208

Я запитав тут: node.js вимагає спадкування?

і мені сказали, що я можу встановити змінні в глобальний масштаб, виключаючи var.

Це не працює для мене.

тобто:

_ = require('underscore');

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

Чи може хтось підтвердити, що це має спрацювати? Дякую.


Звідки у вас вищевказаний рядок?
Ян Ганчич

3
Я думаю, вам не слід починати нове запитання, якщо відповідь на ваше попереднє запитання не працює. Швидше додайте туди коментар і видаліть прийнятий тег.
інопланетянин

5
Якщо тільки редагувати його, він відображається у списку активних питань, що наразі є активними.
МАК

3
Використовуйте exports. Це набагато краще.
Еммерман

1
Можливо, це не працює, тому що ви "використовуєте суворо"; вгорі файлу. Це працює для мене так.
Геза Турі

Відповіді:


237

Ви можете використовувати globalтак:

global._ = require('underscore')

28
Чи можете ви надати трохи більше інформації? Це частина JavaScript або частина вузла? Чи добре це дотримуватися? Як в тому, чи потрібно це робити чи використовувати експрес-набір? Спасибі
Гаррі

4
Попередній коментар невірний. У браузері windowзнаходиться глобальний об'єкт. documentє властивістю window.
G-Wiz

77
Це НЕ є гарною схемою для наслідування. Не робіть цього. Конвенція використання «вимагати» для декупажу модулів добре продумана. Ви не повинні порушувати це без причин, поважної причини. Дивіться мою відповідь нижче.
Дейв Допсон

Глобалів, як правило, слід уникати, але якщо ви дійсно хочете їх використовувати. 3 наведені нижче твердження є еквівалентними і призначать вар для глобальної області застосування: GLOBAL._ = вимагає ("підкреслення"); global._ = вимагати ("підкреслення"); _ = вимагати ("підкреслення");
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 (яку використовує вузол) об'єкт "цей" всередині модуля (тобто "ваш код") НЕ є глобальним контекстом. Для підтвердження цього дивіться нижче, де я розкриваю "цей" об'єкт, а потім гігантський "GLOBAL" об'єкт.

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", щоб забезпечити трохи більшу гнучкість. У таких конфігураційних файлах не було заяв "вимагати", але я хотів, щоб вони мали доступ до підкреслення (система ENTIRE була заснована на шаблонах підкреслення та підкреслення), тому перед оцінкою "конфігурації" я встановила б "GLOBAL._". Так що так, для кожного правила десь є виняток. Але тобі краще мати чортову причину, а не просто "мені набридло набирати" вимагаю ", тому я хочу розірватися з умовою".


7
Які недоліки використання GLOBAL? Навіщо мені потрібна чортова причина? Суть полягає в тому, що моя програма працює, правда?
trusktr

26
Зрештою, так, якщо ви відправляєте, це все, що враховується. Однак певні практики відомі як "найкращі практики" та дотримання їх, як правило, збільшує шанси на доставку та / або можливість підтримувати те, що ви створили. Важливість дотримання «належної практики» збільшується з розміром проекту та його довговічністю. Я вбудував усілякі неприємні хаки в короткочасні проекти, які писали один раз, не читали ніколи (і "єдиний розробник"). У більш масштабному проекті така кутова різка закінчується вартістю проекту.
Дейв Допсон

48
Зокрема, з GLOBAL проблема полягає в читанні. Якщо ваша програма безладно використовує глобальні змінні, це означає, що для розуміння коду я повинен розуміти стан динамічного виконання всього додатка. Ось чому програмісти дивляться на глобальні позиції. Я впевнений, що існує десятки способів їх ефективного використання, але ми здебільшого лише бачили, як молодші програмісти їх зловживають жорстокими продуктами.
Дейв Допсон

2
Чому ви не можете просто поставити свої конфігурації у звичайний .jsфайл та зателефонувати requireперед експортом конфігурацій?
Азат

4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern . якщо те, що ви робите, карти за схемою Сінглтона, то це може мати сенс. З'єднання БД можуть бути одинаковими, коли: 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.

12
Я, звичайно, не люблю єдинорогів, але люблю ваш підхід. Дякую.
Джонатас Уокер

А як із зміною globals.domain?
Fizzix

1
@iLoveUnicorns дякую за відповідь. Я розгляну альтернативи, такі як "експрес-сесія", оскільки мені це головним чином потрібне для зберігання введених даних користувачів.
Fizzix

11
Хоча це, на мою думку, є кращим підходом, він не створює глобальних і не відповідає на поставлене запитання. Це альтернативний підхід, і я завжди закликаю їх дотримуватися, однак суворої задумливості тверджень типу "Це єдина правильна відповідь на цю тему" тут просто не належить. stackoverflow.com/help/be-nice
Thor84no

2
Це може бути кращим підходом, але якщо ви намагаєтеся запускати сценарії із зовнішнім авторським правом, які покладаються на те, що щось знаходиться у глобальному просторі імен, це вам не допоможе. IOW, це не відповідає на питання.
бінкі

12

Як щодо глобального простору імен global.MYAPI = {}

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

Редагувати після коментаря camilo-martin : Усі інші афіші говорять про поганий зразок. Тож залишаючи цю дискусію осторонь, найкращий спосіб визначити змінну глобально (питання ОП) - через простори імен.

@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 / GLOBAL для встановлення будь-якого глобального є поганою практикою, і зовсім не використовувати його теоретично ( теоретично це оперативне слово). Однак (так, оперативний) я використовую це для встановлення спеціальних класів помилок:

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

global.MyError = [Function of MyError];

Так, тут є табу, але якщо ваш сайт / проект використовує власні помилки на всьому місці, вам, головним чином, потрібно визначити його скрізь або принаймні десь:

  1. Визначте клас Error в першу чергу
  2. У сценарії, куди ви його кидаєте
  3. У сценарії, де ви його ловите

Визначення моїх власних помилок у глобальному просторі імен врятує мені клопоту вимагати моєї бібліотеки помилок клієнта. Зображення викидання користувацької помилки, коли ця власна помилка не визначена.

Крім того, якщо це неправильно, то, будь ласка, повідомте мене, оскільки я тільки нещодавно почав це робити

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.