variables globales de node.js?

208

Pregunté aquí: node.js requiere herencia?

y me dijeron que puedo establecer variables en el ámbito global al omitir la var.

Esto no funciona para mi.

es decir:

_ = require('underscore');

No hace que _ esté disponible en los archivos requeridos. Sin app.setembargo, puedo configurarlo con express y tenerlo disponible en otro lugar.

¿Alguien puede confirmar que se supone que esto funciona? Gracias.

Harry
fuente
¿Dónde tienes la línea de arriba?
Jan Hančič
3
Creo que no debería comenzar una nueva pregunta si la respuesta a su pregunta anterior no funciona. Más bien agregue un comentario allí y elimine la etiqueta aceptada.
alienhard
55
Solo editarlo hace que aparezca en la lista de preguntas actualmente activa.
MAK
3
Uso exports. Es mucho, mucho mejor.
Emmerman
1
Tal vez no funciona porque tiene "uso estricto"; en la parte superior de tu archivo. Funciona así para mí.
Geza Turi

Respuestas:

237

Puedes usar globalasí:

global._ = require('underscore')
masylum
fuente
28
¿Podría proporcionar un poco más de información por favor? ¿Es esto parte de javascript o parte del nodo? ¿Es un buen patrón a seguir? ¿Como debería hacer esto o debería usar el set express? Gracias
Harry
44
El comentario anterior es incorrecto. En el navegador, windowes el objeto global. documentes propiedad de window.
G-Wiz
77
Este NO es un buen patrón a seguir. No hagas esto. La convención de usar 'require' para desacoplar módulos está bien pensada. No deberías violarlo sin una buena razón. Vea mi respuesta a continuación.
Dave Dopson
Generalmente se deben evitar los globales, pero si realmente quieres usarlos. Las 3 declaraciones a continuación son todas equivalentes y asignarán una var al alcance global: GLOBAL._ = require ('subrayado'); global._ = require ('guión bajo'); _ = requerir ('guión bajo');
metaColin
Cuando su proyecto comienza a crecer un poco, esto se convertirá en una pesadilla para mantener. Por favor, eche un vistazo a mi enfoque.
Oliver Dixon
219

En el nodo, puede establecer variables globales a través del objeto "global" o "GLOBAL":

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

o más útilmente ...

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

Desde el origen del nodo, puede ver que estos tienen un alias entre sí:

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

En el código anterior, "esto" es el contexto global. Con el sistema de módulos commonJS (qué nodo usa), el objeto "este" dentro de un módulo (es decir, "su código") NO es el contexto global. Para probar esto, vea a continuación donde arrojo el objeto "este" y luego el objeto gigante "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: {} }
*/

** Nota: con respecto a la configuración "GLOBAL._", en general solo debes hacer var _ = require('underscore');. Sí, lo haces en cada archivo que usa guión bajo, al igual que en Java import com.foo.bar;. Esto hace que sea más fácil averiguar qué está haciendo su código porque los enlaces entre archivos son 'explícitos'. Ligeramente molesto, pero algo bueno. .... Esa es la predicación.

Hay una excepción a cada regla. He tenido exactamente UNA instancia en la que necesitaba configurar "GLOBAL._". Estaba creando un sistema para definir archivos "config" que eran básicamente JSON, pero estaban "escritos en JS" para permitir un poco más de flexibilidad. Dichos archivos de configuración no tenían declaraciones 'require', pero quería que tuvieran acceso a guión bajo (el sistema ENTERO se basaba en plantillas de guión bajo y guión bajo), por lo que antes de evaluar la "configuración", establecería "GLOBAL._". Entonces, sí, para cada regla, hay una excepción en alguna parte. Pero es mejor que tenga una buena razón y no solo "me canso de escribir 'require', así que quiero romper con la convención".

Dave Dopson
fuente
77
¿Cuáles son las desventajas de usar GLOBAL? ¿Por qué necesito una buena razón? La conclusión es que mi aplicación funciona, ¿verdad?
trusktr
26
en última instancia, sí, si envía, eso es todo lo que cuenta. Sin embargo, ciertas prácticas se conocen como "mejores prácticas" y seguirlas generalmente aumenta sus probabilidades de envío y / o de poder mantener lo que ha construido. La importancia de seguir las "buenas prácticas" aumenta con el tamaño del proyecto y su longevidad. He incorporado todo tipo de trucos desagradables en proyectos de corta duración que fueron de escritura única, lectura nunca (y "desarrollador único"). En un proyecto más grande, ese tipo de corte de esquinas termina costándole el impulso del proyecto.
Dave Dopson el
48
Específicamente, con GLOBAL, el problema es de legibilidad. Si su programa utiliza promiscuamente variables globales, significa que para comprender el código, debo comprender el estado dinámico de tiempo de ejecución de toda la aplicación. Es por eso que los programadores desconfían de los globales. Estoy seguro de que hay docenas de formas de usarlos de manera efectiva, pero la mayoría de las veces los hemos visto abusados ​​por programadores junior por el mal del producto.
Dave Dopson
2
¿Por qué no puede simplemente poner sus configuraciones en un .jsarchivo normal y llamar requireantes de exportar las configuraciones?
Azat
44
@Jackie - en.wikipedia.org/wiki/Singleton_pattern . si lo que está haciendo se asigna al patrón Singleton, entonces podría tener sentido. Las conexiones de base de datos pueden ser simples cuando: 1) la configuración es costosa, 2) solo desea que la conexión se configure una vez, 3) el objeto de conexión es de larga duración y no entrará en un estado fallido en caso de hipo de la red, 4) el objeto de conexión es seguro para subprocesos / puede ser compartido por muchos llamadores diferentes.
Dave Dopson
78

Las otras soluciones que usan la palabra clave GLOBAL son una pesadilla para mantener / legibilidad (+ contaminación de espacio de nombres y errores) cuando el proyecto se hace más grande. He visto este error muchas veces y tuve la molestia de arreglarlo.

Use un archivo JS y luego use exportaciones de módulos.

Ejemplo:

globals.js

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

module.exports = Globals;

Luego, si desea utilizarlos, use require.

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.
Oliver Dixon
fuente
13
Seguramente no amo a los Unicornios, pero me gusta tu enfoque. Gracias.
Jonatas Walker
¿Pero qué hay de cambiar globals.domain?
Fizzix
1
@iLoveUnicorns gracias por responder. Buscaré alternativas como 'sesión rápida' ya que la necesito principalmente para almacenar los datos de usuario registrados.
Fizzix
11
Si bien esto, en mi opinión, es un mejor enfoque, no crea globales y no responde la pregunta formulada. Es un enfoque alternativo y siempre los alentaría, sin embargo, la arrogancia alcista de declaraciones como "Esta es la única respuesta correcta en este hilo" simplemente no pertenece aquí. stackoverflow.com/help/be-nice
Thor84no
2
Este puede ser un mejor enfoque, pero si está intentando ejecutar scripts creados externamente que se basan en algo que se encuentra en el espacio de nombres global, esto no lo ayuda. IOW, esto no responde la pregunta.
binki
12

¿Qué pasa con un espacio de nombres global como global.MYAPI = {}

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

Edite después del comentario de camilo-martin : Todos los otros carteles hablan sobre el mal patrón involucrado. Dejando a un lado esa discusión, la mejor manera de tener una variable definida globalmente (pregunta de OP) es a través de espacios de nombres.

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

Igor Parra
fuente
3
¡Para eso requireestá! Está bien usar espacios de nombres, pero no vayas a todos global.foo = global.foo || {}los archivos, o algo así. Requerir el archivo que define el espacio de nombres. Hazlo por los niños.
Camilo Martin
@ camilo-martin Hola, 1) Al definir global.MYAPI._ no necesitas definirlo en todos los archivos, esa es la razón de ser global. 2) Esto no tiene que ser con los niños. Incluso si todo dice que es un mal patrón, depende del programador y de la situación dada cómo usa esta capacidad del lenguaje.
Igor Parra
2
Sí, pero supongamos que declara parte de la funcionalidad de un espacio de nombres en un archivo separado. Luego, necesita un archivo para usar el objeto, que está al revés y también va en contra de CommonJS y CommonSense. Si va a requerir cosas, haga que el código de usuario requiera el espacio de nombres y no sea requerido por el espacio de nombres. Tenga en cuenta que no estoy diciendo nada en contra de los espacios de nombres, solo que hay convenciones sobre quién llama a quién por una razón. Y en el lado del cliente no tienes lo que tiene el nodo; Ver el enlace que mencionas está haciendo las cosas de cierta manera (a través de global) porque se trata del navegador y no del nodo.
Camilo Martin
1
Lamentablemente, la URL que publicó solo funciona si omite la barra inclinada;)
Dirigible
10

Simplemente puede usar el objeto global.

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

console.log(x);
//['a', 'b', 'c']
Joao Falcao
fuente
5

Estoy de acuerdo en que usar el espacio de nombres global / GLOBAL para establecer algo global es una mala práctica y no lo uso en absoluto en teoría ( en teoría es la palabra clave). Sin embargo (sí, el operativo) lo uso para configurar clases de error personalizadas:

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

global.MyError = [Function of MyError];

Sí, tabú aquí, pero si su sitio / proyecto usa errores personalizados en todo el lugar, básicamente necesitaría definirlo en todas partes, o al menos en algún lugar para:

  1. Definir la clase Error en primer lugar.
  2. En el guión donde lo estás tirando
  3. En el guión donde lo estás atrapando

Definir mis errores personalizados en el espacio de nombres global me ahorra la molestia de requerir la biblioteca de errores de mi cliente. Imágenes que arrojan un error personalizado donde ese error personalizado no está definido.

Además, si esto está mal, hágamelo saber, ya que recién comencé a hacer esto recientemente.

Escarabajo Borracho
fuente