Variables globales node.js?

208

J'ai demandé ici: node.js nécessite l'héritage?

et on m'a dit que je peux définir des variables à la portée globale en omettant la var.

Cela ne fonctionne pas pour moi.

c'est à dire:

_ = require('underscore');

Ne rend pas le _ disponible sur les fichiers requis. Je peux régler avec expressapp.set et les avoir disponibles ailleurs cependant.

Quelqu'un peut-il confirmer que cela est censé fonctionner? Merci.

Harry
la source
Où avez-vous la ligne ci-dessus?
Jan Hančič
3
Je pense que vous ne devriez pas commencer une nouvelle question si la réponse à votre question précédente ne fonctionne pas. Ajoutez-y plutôt un commentaire et supprimez la balise acceptée.
alienhard
5
Une simple modification le fait apparaître dans la liste des questions actuellement active.
MAK
3
Utilisez exports. C'est beaucoup mieux.
Emmerman
1
Peut-être que cela ne fonctionne pas car vous avez "utiliser strict"; en haut de votre dossier. Cela fonctionne comme ça pour moi.
Geza Turi

Réponses:

237

Vous pouvez utiliser globalcomme ceci:

global._ = require('underscore')
masylum
la source
28
Pourriez-vous fournir un peu plus d'informations s'il vous plaît? Est-ce que cela fait partie du javascript ou fait partie du nœud? Est-ce un bon schéma à suivre? Comme dois-je le faire ou dois-je utiliser un jeu express? Merci
Harry
4
Le commentaire précédent est incorrect. Dans le navigateur, windowest l'objet global. documentest une propriété de window.
G-Wiz
77
Ce n'est PAS un bon modèle à suivre. Ne fais pas ça. La convention d'utilisation de «require» pour découpler les modules est bien pensée. Vous ne devriez pas le violer sans une bonne raison. Voir ma réponse ci-dessous.
Dave Dopson
Les globaux sont généralement à éviter, mais si vous voulez vraiment les utiliser. Les 3 instructions ci-dessous sont toutes équivalentes et affecteront une variable à la portée globale: GLOBAL._ = require ('underscore'); global._ = require ('underscore'); _ = require ('underscore');
metaColin
Lorsque votre projet commence à devenir un peu plus grand, cela deviendra un cauchemar à entretenir. Veuillez jeter un œil à mon approche.
Oliver Dixon
219

Dans le nœud, vous pouvez définir des variables globales via l'objet "global" ou "GLOBAL":

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

ou plus utilement ...

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

Depuis la source du nœud, vous pouvez voir que ceux-ci sont aliasés les uns aux autres:

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

Dans le code ci-dessus, "ceci" est le contexte global. Avec le système de modules commonJS (que le nœud utilise), l'objet "this" à l'intérieur d'un module (c'est-à-dire "votre code") n'est PAS le contexte global. Pour en avoir la preuve, voir ci-dessous où je crache l'objet "this" puis l'objet géant "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: {} }
*/

** Remarque: en ce qui concerne le réglage "GLOBAL._", en général, vous devez simplement le faire var _ = require('underscore');. Oui, vous le faites dans chaque fichier qui utilise le soulignement, tout comme vous le faites en Javaimport com.foo.bar; . Cela facilite la compréhension de ce que fait votre code car les liens entre les fichiers sont «explicites». Légèrement ennuyeux, mais une bonne chose. .... C'est la prédication.

Il y a une exception à chaque règle. J'ai eu exactement exactement UNE instance où je devais définir "GLOBAL._". Je créais un système pour définir des fichiers "config" qui étaient essentiellement JSON, mais qui étaient "écrits en JS" pour permettre un peu plus de flexibilité. De tels fichiers de configuration n'avaient pas d'instructions 'require', mais je voulais qu'ils aient accès au trait de soulignement (le système ENTIRE était basé sur les modèles de soulignement et de soulignement), donc avant d'évaluer la "config", je définirais "GLOBAL._". Alors oui, pour chaque règle, il y a une exception quelque part. Mais vous feriez mieux d'avoir une sacrée bonne raison et pas seulement "je suis fatigué de taper" require "donc je veux rompre avec la convention".

Dave Dopson
la source
7
Quels sont les inconvénients de l'utilisation de GLOBAL? Pourquoi ai-je besoin d'une sacrée bonne raison? L'essentiel est que mon application fonctionne, non?
trusktr
26
en fin de compte, oui, si vous expédiez, c'est tout ce qui compte. Cependant, certaines pratiques sont connues sous le nom de «meilleures pratiques» et les suivre augmente généralement vos chances d'expédition et / ou d'être en mesure de maintenir ce que vous avez construit. L'importance de suivre les «bonnes pratiques» augmente avec la taille du projet et sa longévité. J'ai intégré toutes sortes de hacks désagréables dans des projets de courte durée qui étaient à écriture unique, en lecture (et "à développeur unique"). Dans un projet plus important, ce type de coupe de coin finit par vous coûter l'élan du projet.
Dave Dopson,
48
Plus précisément, avec GLOBAL, le problème est celui de la lisibilité. Si votre programme utilise de manière promisciente des variables globales, cela signifie que pour comprendre le code, je dois comprendre l'état d'exécution dynamique de l'application entière. C'est pourquoi les programmeurs se méfient des globaux. Je suis sûr qu'il existe des dizaines de façons de les utiliser efficacement, mais nous venons juste de les voir abusées par des programmeurs débutants au détriment du produit.
Dave Dopson
2
Pourquoi ne pouvez-vous pas simplement mettre vos configurations dans un .jsfichier normal et appeler requireavant d'exporter les configurations?
Azat
4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern . si ce que vous faites correspond au motif Singleton, cela pourrait avoir du sens. Les connexions DB peuvent être singletons lorsque: 1) la configuration coûte cher, 2) vous ne souhaitez établir la connexion qu'une seule fois, 3) l'objet de connexion a une longue durée de vie et n'entrera pas en état d'échec en cas de hoquet réseau, 4) l'objet de connexion est thread-safe / peut être partagé par de nombreux appelants différents.
Dave Dopson
78

Les autres solutions qui utilisent le mot clé GLOBAL sont un cauchemar pour maintenir / lisibilité (+ pollution de l'espace de noms et bugs) lorsque le projet s'agrandit. J'ai vu cette erreur plusieurs fois et j'ai eu les tracas de la réparer.

Utilisez un fichier JS puis utilisez les exportations de module.

Exemple:

globals.js

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

module.exports = Globals;

Ensuite, si vous souhaitez les utiliser, utilisez require.

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.
Oliver Dixon
la source
13
Je n'aime sûrement pas les licornes mais j'aime votre approche. Merci.
Jonatas Walker
Et globals.domainsi vous changiez?
Fizzix
1
@iLoveUnicorns merci d'avoir répondu. J'examinerai des alternatives telles que «session express» car j'en ai principalement besoin pour stocker les données utilisateur connectées.
Fizzix
11
Bien que cela soit à mon avis une meilleure approche, cela ne crée pas de globaux et ne répond pas à la question posée. C'est une approche alternative et j'encouragerais toujours ceux-ci, mais la pure arrogance haussière des déclarations comme "Ceci est la seule bonne réponse sur ce fil" n'appartiennent tout simplement pas ici. stackoverflow.com/help/be-nice
Thor84no
2
Cela peut être une meilleure approche, mais si vous essayez d'exécuter des scripts créés en externe qui reposent sur quelque chose se trouvant dans l'espace de noms global, cela ne vous aide pas. IOW, cela ne répond pas à la question.
binki
12

Qu'en est-il d'un espace de noms global comme global.MYAPI = {}

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

Modifier après le commentaire de camilo-martin : Toutes les autres affiches parlent du mauvais schéma impliqué. Donc, en laissant cette discussion de côté, la meilleure façon d'avoir une variable définie globalement (question OP) est à travers les espaces de noms.

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

Igor Parra
la source
3
C'est pour ça require! Il est correct d'utiliser des espaces de noms, mais ne faites pas tout global.foo = global.foo || {}sur tous les fichiers ou quelque chose. Exigez le fichier qui définit l'espace de noms. Faites-le pour les enfants.
Camilo Martin
@ camilo-martin Salut, 1) En définissant global.MYAPI._ vous n'avez pas besoin de le définir dans tous les fichiers, c'est la raison d'être global. 2) Ce rien ne doit pas être avec les enfants. Même si tout le monde dit que c'est un mauvais schéma, cela dépend du programmeur et de la situation donnée comment il utilise cette capacité du langage.
Igor Parra
2
Oui, mais disons que vous déclarez certaines des fonctionnalités d'un espace de noms dans un fichier séparé. Ensuite, vous avez besoin d'un fichier pour utiliser l'objet, qui est à l'envers et va également contre CommonJS et CommonSense. Si vous allez avoir besoin de choses, demandez au code utilisateur d'exiger l'espace de noms et de ne pas être requis par l'espace de noms. Notez que je ne dis rien contre les espaces de noms, juste qu'il y a des conventions sur qui appelle qui pour une raison. Et côté client, vous n'avez pas ce que le nœud a; voir le lien que vous mentionnez fait les choses d'une certaine manière (via global) car il s'agit du navigateur et non du nœud.
Camilo Martin
1
Malheureusement, l'URL que vous avez publiée ne fonctionne que si vous omettez la barre oblique de fin;)
Dirigible
10

Vous pouvez simplement utiliser l'objet global.

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

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

Je suis d'accord que l'utilisation de l'espace de noms global / GLOBAL pour définir quelque chose de global est une mauvaise pratique et ne l'utilise pas du tout en théorie ( en théorie étant le mot clé). Cependant (oui, l'opérateur) je l'utilise pour définir des classes d'erreur personnalisées:

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

global.MyError = [Function of MyError];

Oui, tabou ici, mais si votre site / projet utilise des erreurs personnalisées partout, vous devrez essentiellement le définir partout, ou au moins quelque part pour:

  1. Définissez la classe Error en premier lieu
  2. Dans le script où vous le lancez
  3. Dans le script où vous l'attrapez

La définition de mes erreurs personnalisées dans l'espace de noms global m'évite d'avoir à demander ma bibliothèque d'erreurs client. L'imagerie lançant une erreur personnalisée lorsque cette erreur personnalisée n'est pas définie.

De plus, si cela ne va pas, faites-le moi savoir car je viens juste de commencer à le faire récemment

DrunkenBeetle
la source