variabili globali node.js?


208

Ho chiesto qui: node.js richiede l'ereditarietà?

e mi è stato detto che posso impostare variabili nell'ambito globale lasciando fuori la var.

Questo non funziona per me.

vale a dire:

_ = require('underscore');

Non rende _ disponibile sui file richiesti. Posso impostare con Express app.sete averlo disponibile altrove.

Qualcuno può confermare che questo dovrebbe funzionare? Grazie.


Dove hai la linea sopra?
Jan Hančič,

3
Penso che non dovresti iniziare una nuova domanda se la risposta alla tua domanda precedente non funziona. Piuttosto aggiungi un commento lì e rimuovi il tag accettato.
alienhard

5
Basta modificarlo per farlo apparire nell'elenco delle domande attualmente attive.
MAK,

3
Usa exports. È molto meglio.
Emmerman,

1
Forse non funziona perché hai "usare rigoroso"; nella parte superiore del file. Funziona così per me.
Geza Turi,

Risposte:


237

Puoi usare globalcosì:

global._ = require('underscore')

28
Potresti fornire qualche informazione in più per favore? Questa parte di javascript o parte del nodo? È un buon modello da seguire? Come dovrei fare questo o dovrei usare express set? Grazie
Harry,

4
Il commento precedente non è corretto. Nel browser, windowè l'oggetto globale. documentè di proprietà di window.
G-Wiz,

77
Questo NON è un buon modello da seguire. Non farlo La convenzione di usare "richiede" per disaccoppiare i moduli è ben pensata. Non dovresti violarlo senza una buona ragione. Vedi la mia risposta qui sotto.
Dave Dopson,

I globuli vanno generalmente evitati, ma se si vuole davvero usarli. Le 3 seguenti affermazioni sono tutte equivalenti e assegneranno una var all'ambito globale: GLOBAL._ = require ('underscore'); global._ = require ('underscore'); _ = request ('trattino basso');
metaColin

Quando il tuo progetto inizia a diventare un po 'più grande, questo diventerà un incubo da mantenere. Per favore, dai un'occhiata al mio approccio.
Oliver Dixon,

219

Nel nodo, è possibile impostare variabili globali tramite l'oggetto "globale" o "GLOBALE":

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

o più utilmente ...

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

Dalla sorgente del nodo, puoi vedere che sono aliasati tra loro:

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

Nel codice sopra, "questo" è il contesto globale. Con il sistema di moduli commonJS (quale nodo utilizza), l'oggetto "this" all'interno di un modulo (cioè "il tuo codice") NON è il contesto globale. Per prova di ciò, vedi sotto dove vomito l'oggetto "questo" e poi il gigantesco oggetto "GLOBALE".

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: per quanto riguarda l'impostazione "GLOBAL._", in generale dovresti semplicemente farlo var _ = require('underscore');. Sì, lo fai in ogni singolo file che utilizza il trattino basso, proprio come in Java import com.foo.bar;. Questo rende più facile capire cosa sta facendo il tuo codice perché i collegamenti tra i file sono "espliciti". Leggermente fastidioso, ma una buona cosa. .... Questa è la predicazione.

C'è un'eccezione per ogni regola. Ho avuto esattamente UN'istanza in cui dovevo impostare "GLOBAL._". Stavo creando un sistema per la definizione di file "config" fondamentalmente JSON, ma "scritti in JS" per consentire un po 'più di flessibilità. Tali file di configurazione non avevano dichiarazioni 'richiedono', ma volevo che avessero accesso al carattere di sottolineatura (il sistema INTERO era basato su modelli di trattino basso e di sottolineatura), quindi prima di valutare "config", avrei impostato "GLOBAL._". Quindi sì, per ogni regola, c'è un'eccezione da qualche parte. Ma faresti meglio ad avere una buona ragione e non solo "mi stanco di scrivere 'richiedi' quindi voglio rompere con le convenzioni".


7
Quali sono gli svantaggi dell'utilizzo di GLOBAL? Perché ho bisogno di un maledetto motivo? La linea di fondo è che la mia app funziona, giusto?
trusktr,

26
alla fine sì, se spedisci, è tutto ciò che conta. Tuttavia, alcune pratiche sono note come "migliori pratiche" e seguirle aumenta in genere le tue probabilità di spedizione e / o la capacità di mantenere ciò che hai costruito. L'importanza di seguire le "buone pratiche" aumenta con la dimensione del progetto e la sua longevità. Ho creato tutti i tipi di attacchi dannosi in progetti di breve durata che sono stati scrivere una volta, non leggere mai (e "single-developer"). In un progetto più grande, quel tipo di taglio degli angoli finisce per costarti lo slancio del progetto.
Dave Dopson,

48
In particolare, con GLOBAL, il problema è di leggibilità. Se il tuo programma utilizza in modo promiscuo variabili globali, significa che per comprendere il codice, devo capire lo stato di runtime dinamico dell'intera app. Questo è il motivo per cui i programmatori sono diffidenti nei confronti dei globali. Sono sicuro che ci sono dozzine di modi per usarli in modo efficace, ma per lo più li abbiamo appena visti abusati dai programmatori junior per i malati del prodotto.
Dave Dopson,

2
Perché non puoi semplicemente mettere le tue configurazioni in un .jsfile normale e chiamare requireprima di esportare le configurazioni?
Azat,

4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern . se quello che stai facendo è mappato al modello Singleton, allora potrebbe avere senso. Le connessioni DB possono essere singleton quando: 1) l'installazione è costosa, 2) si desidera impostare la connessione solo una volta, 3) l'oggetto di connessione è di lunga durata e non entrerà in uno stato non riuscito in caso di singhiozzi di rete, 4) l'oggetto connessione è thread-safe / può essere condiviso da molti chiamanti diversi.
Dave Dopson,

78

Le altre soluzioni che utilizzano la parola chiave GLOBAL sono un incubo da mantenere / leggibilità (+ inquinamento dello spazio dei nomi e bug) quando il progetto diventa più grande. Ho visto questo errore molte volte e ho avuto il fastidio di risolverlo.

Utilizzare un file JS quindi utilizzare le esportazioni del modulo.

Esempio:

globals.js

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

module.exports = Globals;

Quindi, se si desidera utilizzare questi, utilizzare richiedono.

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.

13
Sicuramente non amo gli unicorni ma mi piace il tuo approccio. Grazie.
Jonatas Walker,

Che dire di cambiare globals.domainperò?
Fizzix,

1
@iLoveUnicorns grazie per la risposta. Esaminerò alternative come "express-session" poiché ne ho principalmente bisogno per archiviare i dati dell'utente registrato.
Fizzix,

11
Anche se secondo me questo è un approccio migliore, non crea globuli e non risponde alla domanda posta. È un approccio alternativo e incoraggio sempre quelli, tuttavia la pura arroganza rialzista di affermazioni come "Questa è l'unica risposta corretta su questo thread" semplicemente non appartiene a questo. stackoverflow.com/help/be-nice
Thor84no

2
Questo potrebbe essere un approccio migliore, ma se stai cercando di eseguire script creati esternamente che si basano su qualcosa che si trova nello spazio dei nomi globale, questo non ti aiuta. IOW, questo non risponde alla domanda.
binki,

12

Che dire di uno spazio dei nomi globale come global.MYAPI = {}

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

Modifica dopo il commento di Camilo-Martin : tutti gli altri poster parlano del cattivo modello in questione. Quindi, lasciando da parte quella discussione, il modo migliore per avere una variabile definita a livello globale (domanda di OP) è attraverso gli spazi dei nomi.

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


3
Ecco a cosa requireserve! Va bene usare gli spazi dei nomi, ma non andare tutto global.foo = global.foo || {}su tutti i file o qualcosa del genere. Richiedi il file che definisce lo spazio dei nomi. Fallo per i bambini.
Camilo Martin,

@ camilo-martin Ciao, 1) Definendo global.MYAPI._ non è necessario definirlo in tutti i file, questa è la ragione per essere globale. 2) Questo niente deve essere con i bambini. Anche se tutto dice che è un cattivo modello, dipende dal programmatore e dalla data situazione in cui usa questa capacità della lingua.
Igor Parra,

2
Sì, ma supponiamo che tu dichiari alcune delle funzionalità di uno spazio dei nomi in un file separato. Quindi è necessario un file per utilizzare l'oggetto, che è all'indietro e va anche contro CommonJS e CommonSense. Se hai bisogno di cose, fai in modo che il codice utente richieda lo spazio dei nomi e non sia richiesto dallo spazio dei nomi. Nota non sto dicendo nulla contro gli spazi dei nomi, solo che ci sono convenzioni su chi chiama chi per un motivo. E nel lato client non hai quello che ha il nodo; vedi il link che menzioni sta facendo le cose in un certo modo (attraverso globale) perché riguarda il browser e non il nodo.
Camilo Martin,

1
Purtroppo l'URL che hai pubblicato funziona solo se lasci fuori la barra finale;)
Dirigible

10

Puoi semplicemente usare l'oggetto globale.

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

console.log(x);
//['a', 'b', 'c']

5

Sono d'accordo che l'uso dello spazio dei nomi globale / GLOBALE per impostare qualcosa di globale è una cattiva pratica e non lo uso affatto in teoria ( in teoria è la parola chiave). Tuttavia (sì, il operativo) lo uso per impostare classi di errore personalizzate:

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

global.MyError = [Function of MyError];

Sì, tabù qui, ma se il tuo sito / progetto utilizza errori personalizzati in tutto il luogo, dovresti sostanzialmente definirlo ovunque, o almeno da qualche parte per:

  1. Definire innanzitutto la classe Error
  2. Nella sceneggiatura in cui la stai lanciando
  3. Nella sceneggiatura in cui la stai catturando

Definire i miei errori personalizzati nello spazio dei nomi globale mi evita il fastidio di richiedere la mia libreria di errori del cliente. L'imaging genera un errore personalizzato in cui tale errore personalizzato non è definito.

Inoltre, se questo è sbagliato, per favore fatemi sapere come ho appena iniziato a farlo di recente

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.