Knoten.js globale Variablen?

208

Ich fragte hier: node.js erfordern Vererbung?

und mir wurde gesagt, dass ich Variablen auf den globalen Bereich setzen kann, indem ich die Variable weglasse.

Das funktioniert bei mir nicht.

dh:

_ = require('underscore');

Stellt das _ für die erforderlichen Dateien nicht zur Verfügung. Ich kann mit Express einstellen app.setund habe es aber woanders verfügbar.

Kann jemand bestätigen, dass dies funktionieren soll? Vielen Dank.

Harry
quelle
Wo hast du die obige Zeile?
Jan Hančič
3
Ich denke, Sie sollten keine neue Frage stellen, wenn die Antwort auf Ihre vorherige Frage nicht funktioniert. Fügen Sie dort lieber einen Kommentar hinzu und entfernen Sie das akzeptierte Tag.
Alienhard
5
Wenn Sie es nur bearbeiten, wird es in der Liste der aktuell aktiven Fragen angezeigt.
MAK
3
Verwenden Sie exports. Es ist viel viel besser.
Emmerman
1
Vielleicht funktioniert es nicht, weil Sie "strenge verwenden"; oben in Ihrer Datei. Bei mir funktioniert das so.
Geza Turi

Antworten:

237

Sie können globalwie folgt verwenden:

global._ = require('underscore')
Masylum
quelle
28
Könnten Sie bitte ein bisschen mehr Informationen geben? Ist dieser Teil von Javascript oder Teil von Node? Ist es ein gutes Muster zu folgen? Wie soll ich das machen oder soll ich Express-Set verwenden? Danke
Harry
4
Der vorherige Kommentar ist falsch. Im Browser windowist das globale Objekt. documentist eine Eigenschaft von window.
G-Wiz
77
Dies ist KEIN gutes Muster. Tu das nicht. Die Konvention der Verwendung von 'require' zum Entkoppeln von Modulen ist gut durchdacht. Sie sollten es nicht ohne guten Grund verletzen. Siehe meine Antwort unten.
Dave Dopson
Globals sind generell zu vermeiden, aber wenn Sie sie wirklich nutzen wollen. Die drei folgenden Anweisungen sind alle gleichwertig und weisen dem globalen Bereich eine Variable zu: GLOBAL._ = require ('Unterstrich'); global._ = require ('Unterstrich'); _ = erfordern ('Unterstrich');
MetaColin
Wenn Ihr Projekt etwas größer wird, wird dies zu einem Albtraum. Bitte werfen Sie einen Blick auf meinen Ansatz.
Oliver Dixon
219

Im Knoten können Sie globale Variablen über das Objekt "global" oder "GLOBAL" festlegen:

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

oder nützlicher ...

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

An der Knotenquelle können Sie erkennen, dass diese zueinander ausgerichtet sind:

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

Im obigen Code ist "dies" der globale Kontext. Beim commonJS-Modulsystem (welcher Knoten verwendet) ist das "this" -Objekt innerhalb eines Moduls (dh "Ihr Code") NICHT der globale Kontext. Zum Beweis siehe unten, wo ich das "this" -Objekt und dann das riesige "GLOBAL" -Objekt ausspucke.

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: {} }
*/

** Hinweis: In Bezug auf die Einstellung "GLOBAL._" sollten Sie dies im Allgemeinen einfach tun var _ = require('underscore');. Ja, Sie tun dies in jeder einzelnen Datei, die Unterstriche verwendet, genau wie in Javaimport com.foo.bar; . Dies macht es einfacher herauszufinden, was Ihr Code tut, da die Verknüpfungen zwischen Dateien "explizit" sind. Leicht nervig, aber eine gute Sache. .... das ist die Predigt.

Zu jeder Regel gibt es eine Ausnahme. Ich hatte genau genau eine Instanz, in der ich "GLOBAL._" setzen musste. Ich habe ein System zum Definieren von "Konfigurations" -Dateien erstellt, die im Grunde JSON waren, aber "in JS geschrieben" wurden, um etwas mehr Flexibilität zu ermöglichen. Solche Konfigurationsdateien hatten keine "require" -Anweisungen, aber ich wollte, dass sie Zugriff auf Unterstriche haben (das GESAMTE System basiert auf Unterstrichen und Unterstrichvorlagen). Bevor ich die "config" auswerte, setzte ich "GLOBAL._". Also ja, für jede Regel gibt es irgendwo eine Ausnahme. Aber du solltest besser einen verdammt guten Grund haben und nicht nur "ich habe es satt, 'require' zu tippen, also möchte ich mit der Konvention brechen".

Dave Dopson
quelle
7
Was sind die Nachteile der Verwendung von GLOBAL? Warum brauche ich einen verdammt guten Grund? Das Fazit ist, dass meine App funktioniert, oder?
Trusktr
26
Letztendlich, ja, wenn Sie versenden, ist das alles, was zählt. Bestimmte Vorgehensweisen werden jedoch als "Best Practices" bezeichnet. Wenn Sie diese befolgen, erhöhen Sie in der Regel die Wahrscheinlichkeit, dass Sie versenden und / oder das, was Sie erstellt haben, beibehalten können. Die Bedeutung der Befolgung "bewährter Verfahren" steigt mit der Größe des Projekts und seiner Langlebigkeit. Ich habe alle Arten von fiesen Hacks in kurzlebige Projekte eingebaut, die einmal geschrieben, nie gelesen (und "Einzelentwickler") waren. In einem größeren Projekt kostet diese Art des Eckenschneidens Ihre Projektdynamik.
Dave Dopson
48
Bei GLOBAL geht es insbesondere um Lesbarkeit. Wenn Ihr Programm promisku globale Variablen verwendet, bedeutet dies, dass ich zum Verständnis des Codes den dynamischen Laufzeitstatus der gesamten App verstehen muss. Aus diesem Grund sind Programmierer misstrauisch gegenüber Globalen. Ich bin mir sicher, dass es Dutzende von Möglichkeiten gibt, sie effektiv zu nutzen, aber wir haben sie meistens nur von Junior-Programmierern missbraucht gesehen, um die Krankheit des Produkts zu bekämpfen.
Dave Dopson
2
Warum können Sie Ihre Konfigurationen nicht einfach in eine reguläre .jsDatei einfügen und aufrufen, requirebevor Sie die Konfigurationen exportieren?
Azat
4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern . Wenn das, was Sie tun, dem Singleton-Muster zugeordnet ist, ist dies möglicherweise sinnvoll. DB-Verbindungen können Singletons sein, wenn: 1) die Einrichtung teuer ist, 2) die Verbindung nur einmal hergestellt werden soll, 3) das Verbindungsobjekt langlebig ist und bei Netzwerkproblemen nicht in einen fehlerhaften Zustand übergeht, 4) Das Verbindungsobjekt ist threadsicher und kann von vielen verschiedenen Anrufern gemeinsam genutzt werden.
Dave Dopson
78

Die anderen Lösungen, die das Schlüsselwort GLOBAL verwenden, sind ein Albtraum für die Aufrechterhaltung / Lesbarkeit (+ Verschmutzung des Namespaces und Fehler), wenn das Projekt größer wird. Ich habe diesen Fehler oft gesehen und hatte die Mühe, ihn zu beheben.

Verwenden Sie eine JS-Datei und dann Modulexporte.

Beispiel:

globals.js

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

module.exports = Globals;

Wenn Sie diese verwenden möchten, verwenden Sie require.

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.
Oliver Dixon
quelle
12
Ich liebe Einhörner sicherlich nicht, aber ich mag deinen Ansatz. Vielen Dank.
Jonatas Walker
Was ist mit Veränderungen globals.domain?
Fizzix
1
@ iLoveUnicorns danke für die Antwort. Ich werde nach Alternativen wie "Express-Sitzung" suchen, da ich diese hauptsächlich zum Speichern der angemeldeten Benutzerdaten benötige.
Fizzix
11
Dies ist meiner Meinung nach ein besserer Ansatz, schafft jedoch keine globalen Elemente und beantwortet die gestellte Frage nicht. Es ist ein alternativer Ansatz und ich würde diese immer ermutigen, aber die schiere bullische Übermut von Aussagen wie "Dies ist die einzig richtige Antwort auf diesen Thread" gehört einfach nicht hierher. stackoverflow.com/help/be-nice
Thor84no
2
Dies mag ein besserer Ansatz sein, aber wenn Sie versuchen, extern erstellte Skripte auszuführen, die davon abhängen, dass sich etwas im globalen Namespace befindet, hilft Ihnen dies nicht weiter. IOW, das beantwortet die Frage nicht.
Binki
12

Wie wäre es mit einem globalen Namespace? global.MYAPI = {}

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

Nach dem Kommentar von Camilo-Martin bearbeiten : Alle anderen Poster sprechen über das schlechte Muster. Abgesehen von dieser Diskussion ist der beste Weg, eine Variable global zu definieren (OP-Frage), Namespaces.

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

Igor Parra
quelle
3
Dafür requireist da! Es ist in Ordnung, Namespaces zu verwenden, aber nicht global.foo = global.foo || {}alle Dateien oder ähnliches. Benötigen Sie die Datei, die den Namespace definiert. Tu es für die Kinder.
Camilo Martin
@ camilo-martin Hallo, 1) Wenn du global.MYAPI._ definierst, musst du es nicht in allen Dateien definieren. Das ist der Grund, global zu sein. 2) Das muss nichts mit den Kindern sein. Selbst wenn alle sagen, dass dies ein schlechtes Muster ist, hängt es vom Programmierer und der gegebenen Situation ab, wie er diese Fähigkeit der Sprache verwendet.
Igor Parra
2
Ja, aber nehmen wir an, Sie deklarieren einige Funktionen eines Namespace in einer separaten Datei. Dann benötigen Sie eine Datei, um das Objekt zu verwenden, das rückwärts ist und auch gegen CommonJS und CommonSense verstößt. Wenn Sie etwas benötigen, muss der Benutzercode den Namespace und nicht den Namespace erfordern. Hinweis: Ich sage nichts gegen Namespaces, nur dass es Konventionen gibt, wer wen aus einem bestimmten Grund anruft. Und auf der Clientseite haben Sie nicht den Knoten. Siehe den Link, den Sie erwähnen, der Dinge auf eine bestimmte Art und Weise (über global) erledigt, weil es um den Browser und nicht um den Knoten geht.
Camilo Martin
1
Leider funktioniert die von Ihnen gepostete URL nur, wenn Sie den abschließenden Schrägstrich weglassen;)
Dirigible
10

Sie können einfach das globale Objekt verwenden.

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

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

Ich bin damit einverstanden, dass die Verwendung des globalen / GLOBAL-Namespace zum Festlegen von globalen Elementen eine schlechte Praxis ist und theoretisch überhaupt nicht verwendet wird ( theoretisch ist dies das operative Wort). Allerdings (ja, der Operative) verwende ich es zum Festlegen benutzerdefinierter Fehlerklassen:

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

global.MyError = [Function of MyError];

Ja, hier tabu, aber wenn Ihre Site / Ihr Projekt überall benutzerdefinierte Fehler verwendet, müssen Sie diese grundsätzlich überall oder zumindest irgendwo definieren, um:

  1. Definieren Sie zunächst die Fehlerklasse
  2. In dem Skript, in das Sie es werfen
  3. In dem Skript, in dem Sie es fangen

Das Definieren meiner benutzerdefinierten Fehler im globalen Namespace erspart mir den Aufwand, meine Kundenfehlerbibliothek zu benötigen. Imaging löst einen benutzerdefinierten Fehler aus, bei dem dieser benutzerdefinierte Fehler undefiniert ist.

Wenn dies auch falsch ist, lassen Sie es mich bitte wissen, da ich gerade erst damit begonnen habe

DrunkenBeetle
quelle