variáveis ​​globais do node.js.?

208

Eu perguntei aqui: node.js requer herança?

e me disseram que eu posso definir variáveis ​​para o escopo global deixando de fora o var.

Isso não funciona para mim.

ou seja:

_ = require('underscore');

Não disponibiliza o _ nos arquivos necessários. Eu posso definir com expresso app.sete tê-lo disponível em outro lugar embora.

Alguém pode confirmar que isso deve funcionar? Obrigado.

atormentar
fonte
Onde você tem a linha acima?
Jan Hančič 27/03
3
Eu acho que você não deve iniciar uma nova pergunta se a resposta à sua pergunta anterior não funcionar. Em vez disso, adicione um comentário e remova a tag aceita.
alienhard
5
A edição apenas faz com que apareça na lista de perguntas ativas no momento.
MAK
3
Use exports. Está muito, muito melhor.
Emmerman
1
Talvez não funcione porque você tem "use strict"; na parte superior do seu arquivo. Funciona assim para mim.
Geza Turi

Respostas:

237

Você pode usar globalassim:

global._ = require('underscore')
masilo
fonte
28
Você poderia fornecer um pouco mais de informações, por favor? Isso faz parte do javascript ou parte do nó? É um bom padrão a seguir? Como devo fazer isso ou devo usar o conjunto expresso? Obrigado
Harry
4
O comentário anterior está incorreto. No navegador, windowé o objeto global. documenté uma propriedade de window.
G-Wiz
77
Este NÃO é um bom padrão a seguir. Não faça isso. A convenção de usar 'require' para desacoplar módulos é bem pensada. Você não deve violá-lo sem uma boa razão. Veja minha resposta abaixo.
31812 Dave Dopson
Globais geralmente devem ser evitados, mas se você realmente quiser usá-los. As três instruções abaixo são todas equivalentes e atribuirão uma var ao escopo global: GLOBAL._ = require ('underscore'); global._ = require ('sublinhado'); _ = require ('sublinhado');
MetaColin 5/05
Quando seu projeto começa a ficar um pouco maior, isso se tornará um pesadelo para manter. Por favor, dê uma olhada na minha abordagem.
Oliver Dixon
219

No nó, você pode definir variáveis ​​globais por meio do objeto "global" ou "GLOBAL":

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

ou mais útil ...

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

Na origem do nó, você pode ver que esses são alias entre si:

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

No código acima, "this" é o contexto global. Com o sistema de módulo commonJS (que o nó usa), o objeto "this" dentro de um módulo (ou seja, "seu código") NÃO é o contexto global. Para provar isso, veja abaixo onde eu vomito o objeto "this" e o objeto "GLOBAL" gigante.

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: em relação à configuração "GLOBAL._", em geral você deve fazer var _ = require('underscore');. Sim, você faz isso em todos os arquivos que usam sublinhado, assim como em Java import com.foo.bar;. Isso torna mais fácil descobrir o que seu código está fazendo porque as ligações entre os arquivos são 'explícitas'. Um pouco irritante, mas uma coisa boa. .... Essa é a pregação.

Há uma exceção a todas as regras. Eu tive exatamente exatamente UMA instância em que precisei definir "GLOBAL._". Eu estava criando um sistema para definir arquivos "config" que eram basicamente JSON, mas foram "escritos em JS" para permitir um pouco mais de flexibilidade. Esses arquivos de configuração não tinham instruções 'exigem', mas eu queria que eles tivessem acesso ao sublinhado (o sistema INTIRE era baseado em modelos de sublinhado e sublinhado); portanto, antes de avaliar a "configuração", eu definiria "GLOBAL._". Então, sim, para todas as regras, há uma exceção em algum lugar. Mas é melhor você ter um bom motivo, e não apenas "eu me canso de digitar 'exigir', então quero romper com a convenção".

Dave Dopson
fonte
7
Quais são as falhas do uso do GLOBAL? Por que preciso de um bom motivo? A conclusão é que meu aplicativo funciona, certo?
trusktr
26
em última análise, sim, se você enviar, isso é tudo o que importa. No entanto, certas práticas são conhecidas como "melhores práticas" e segui-las geralmente aumenta suas chances de envio e / ou de poder manter o que você criou. A importância de seguir as "boas práticas" aumenta com o tamanho do projeto e sua longevidade. Eu construí todos os tipos de hackers desagradáveis ​​em projetos de curta duração que eram de gravação única, leitura nunca (e "desenvolvedor único"). Em um projeto maior, esse tipo de corte de canto acaba custando o momento do projeto.
Dave Dopson
48
Especificamente, com GLOBAL, o problema é de legibilidade. Se seu programa usar variáveis ​​globais de maneira promíscua, isso significa que, para entender o código, devo entender o estado de tempo de execução dinâmico de todo o aplicativo. É por isso que os programadores desconfiam dos globais. Tenho certeza de que há dezenas de maneiras de usá-los de maneira eficaz, mas na maioria das vezes os vimos abusados ​​por programadores juniores devido ao mal do produto.
Dave Dopson
2
Por que você não pode simplesmente colocar suas configurações em um .jsarquivo comum e ligar requireantes de exportar as configurações?
Azat
4
@Jackie - pt.wikipedia.org/wiki/Singleton_pattern . se o que você está fazendo mapeia para o padrão Singleton, pode fazer sentido. As conexões de banco de dados podem ser singletons quando: 1) a configuração é cara, 2) você deseja que a conexão seja configurada apenas uma vez, 3) o objeto de conexão tem vida longa e não entra em um estado de falha no caso de soluços na rede, 4) o objeto de conexão é seguro para thread / pode ser compartilhado por muitos chamadores diferentes.
Dave Dopson
78

As outras soluções que usam a palavra-chave GLOBAL são um pesadelo para manter / legibilidade (+ poluição do namespace e bugs) quando o projeto fica maior. Eu já vi esse erro muitas vezes e tive o trabalho de corrigi-lo.

Use um arquivo JS e use as exportações do módulo.

Exemplo:

globals.js

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

module.exports = Globals;

Então, se você quiser usá-los, use require.

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.
Oliver Dixon
fonte
12
Eu certamente não amo unicórnios, mas gosto da sua abordagem. Obrigado.
precisa
Mas que tal mudar globals.domain?
Fizzix 28/05
1
@iLoveUnicorns obrigado por responder. Examinarei alternativas como 'sessão expressa', pois preciso principalmente dela para armazenar os dados do usuário conectado.
Fizzix 29/05
11
Embora isso, na minha opinião, seja uma abordagem melhor, ele não cria globais e não responde à pergunta. É uma abordagem alternativa e eu sempre os incentivaria, no entanto, a arrogância altista e otimista de declarações como "Esta é a única resposta correta nesse tópico" simplesmente não pertence aqui. stackoverflow.com/help/be-nice
Thor84no 08/08
2
Essa pode ser uma abordagem melhor, mas se você estiver tentando executar scripts de autor externa que dependem de algo que esteja no espaço de nomes global, isso não ajudará. IOW, isso não responde à pergunta.
binki
12

Que tal um espaço para nome global como global.MYAPI = {}

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

Editar após o comentário de camilo-martin : Todos os outros pôsteres falam sobre o mau padrão envolvido. Portanto, deixando essa discussão de lado, a melhor maneira de definir uma variável globalmente (a pergunta do OP) é ​​através de espaços para nome.

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

Igor Parra
fonte
3
É para isso que requireserve! Não há problema em usar espaços para nome, mas não use todos global.foo = global.foo || {}os arquivos ou algo assim. Exija o arquivo que define o espaço para nome. Faça isso pelas crianças.
Camilo Martin
@ camilo-martin Oi, 1) Ao definir global.MYAPI._, você não precisa defini-lo em todos os arquivos. Essa é a razão de ser global. 2) Isso não tem nada a ver com as crianças. Mesmo que tudo diga que esse é um padrão ruim, depende do programador e da situação em que ele usa essa capacidade da linguagem.
Igor Parra
2
Sim, mas digamos que você declare algumas das funcionalidades de um espaço para nome em um arquivo separado. Então você está exigindo que um arquivo use o objeto, que é inverso e vai contra o CommonJS e o CommonSense também. Se você precisar de coisas, peça ao código do usuário que exija o espaço para nome e não seja exigido pelo espaço para nome. Observe que não estou dizendo nada contra espaços para nome, apenas que há convenções sobre quem liga para quem por um motivo. E no lado do cliente, você não tem qual nó tem; veja o link que você menciona está fazendo as coisas de uma certa maneira (por meio de global) porque se trata do navegador e não do nó.
Camilo Martin
1
Infelizmente o URL só postou funciona se você deixar de fora a barra final;)
Dirigível
10

Você pode apenas usar o objeto global.

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

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

Concordo que o uso do espaço de nomes global / GLOBAL para definir algo global é uma prática ruim e não o utiliza em teoria ( em teoria, é a palavra operativa). No entanto (sim, o dispositivo) eu o uso para definir classes de erro personalizadas:

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

global.MyError = [Function of MyError];

Sim, tabu aqui, mas se o seu site / projeto usar erros personalizados em todo o local, você basicamente precisará defini-lo em qualquer lugar ou pelo menos em algum lugar para:

  1. Defina a classe Error em primeiro lugar
  2. No script em que você está jogando
  3. No script onde você está pegando

Definir meus erros personalizados no namespace global me poupa o trabalho de exigir a minha biblioteca de erros do cliente. Imagem gerando um erro personalizado em que esse erro personalizado é indefinido.

Também, se isso estiver errado, entre em contato, pois eu comecei a fazer isso recentemente

BêbadoBesouro
fonte