node.js全局变量?


208

我在这里问: node.js是否需要继承?

有人告诉我可以通过省略var将变量设置为全局范围。

这对我不起作用。

即:

_ = require('underscore');

不能使_在必需文件上可用。我可以设置express app.set,但可以在其他地方使用。

有人可以确认这应该起作用吗?谢谢。


您在上面的那一行?
JanHančič2011年

3
如果您对上一个问题的答案不起作用,我认为您不应该开始一个新问题。而是在此处添加评论并删除接受的标签。
Alienhard

5
只需对其进行编辑,它就会显示在当前活动的问题列表中。
MAK

3
使用exports。好多了。
Emmerman

1
也许因为“使用严格”而无法使用;在文件顶部。对我来说,它就像那样。
Geza Turi

Answers:


237

您可以这样使用global

global._ = require('underscore')

28
您能否提供更多信息?这是javascript的一部分还是节点的一部分?这是遵循的好模式吗?就像我应该这样做还是应该使用Express Set?谢谢
哈利

4
先前的评论不正确。在浏览器中,window是全局对象。document是的属性window
G-Wiz

77
这不是遵循的好模式。不要这样 深思熟虑了使用“ require”将模块解耦的惯例。没有充分的理由就不应违反它。请在下面查看我的回复。
戴夫·多普森

通常应避免使用全局变量,但是如果您真的想使用它们。下面的3条语句都是等效的,并将为全局范围分配一个var:GLOBAL._ = require('underscore'); global._ = require('下划线'); _ = require('下划线');
metaColin

当您的项目开始变得更大时,这将成为噩梦。请看看我的方法。
奥利弗·迪克森

219

在节点中,可以通过“ global”或“ GLOBAL”对象设置全局变量:

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

或更有用的...

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

从节点源,您可以看到它们是彼此别名的:

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

在上面的代码中,“ this”是全局上下文。对于commonJS模块系统(该节点使用哪个节点),模块内部的“ this”对象(即“您的代码”)不是全局上下文。为了证明这一点,请参见下面我在哪里喷出“ this”对象,然后喷出巨大的“ 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: {} }
*/

**注意:关于设置“ GLOBAL._”,通常您应该这样做var _ = require('underscore');。是的,您可以在每个使用下划线的文件中执行此操作,就像在Java中一样import com.foo.bar;。由于文件之间的链接是“显式的”,因此这使查找代码的工作变得更加容易。轻度烦人,但这是一件好事。....这就是说教。

每个规则都有一个例外。我刚好有一个实例需要设置“ GLOBAL._”。我正在创建一个用于定义“ config”文件的系统,这些文件基本上是JSON,但是是用JS编写的,以提供更多的灵活性。这样的配置文件没有'require'语句,但是我希望它们能够使用下划线(整个系统基于下划线和下划线模板为前提),因此在评估“ config”之前,我将设置“ GLOBAL._”。是的,对于每条规则,某处都有一个例外。但是您最好有充分的理由,而不仅仅是“我厌倦了键入'require',所以我想打破常规”。


7
使用GLOBAL的缺点是什么?为什么我需要一个很好的理由?底线是我的应用程序正常工作,对吧?
trusktr 2012年

26
最终,是的,如果您发货,那就很重要了。但是,某些实践被称为“最佳实践”,遵循这些实践通常会增加运输的机率和/或能够维护自己的产品。遵循“良好实践”的重要性随着项目规模的增加和寿命的延长而增加。我已经将各种讨厌的黑客构建到了一次只能写一次,永不读(和“单个开发人员”)的短期项目中。在更大的项目中,这种切角最终会浪费您的项目动力。
戴夫·多普森

48
具体地说,对于GLOBAL,问题是可读性之一。如果您的程序混杂使用全局变量,则意味着为了理解代码,我必须了解整个应用程序的动态运行时状态。这就是为什么程序员不喜欢全局变量的原因。我敢肯定,有数十种方法可以有效地使用它们,但是我们大多数情况下只是看到它们被初级程序员滥用,以致不适用于产品。
戴夫·多普森

2
为什么不能只将配置放入常规.js文件中并require在导出配置之前调用?
Azat 2013年

4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern。如果您正在执行的操作映射到Singleton模式,则可能有意义。在以下情况下,数据库连接可以是单例:1)设置昂贵,2)您只希望建立一次连接,3)连接对象是长期存在的,并且在出现网络故障时不会进入失败状态, 4)连接对象是线程安全的/可以被许多不同的调用者共享。
Dave Dopson,2015年

78

使用GLOBAL关键字的其他解决方案是在项目变大时进行维护/提高可读性的噩梦(+名称空间污染和错误)。我已经多次看到此错误,并且有解决它的麻烦。

使用JS文件,然后使用模块导出。

例:

globals.js

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

module.exports = Globals;

然后,如果要使用这些,请使用require。

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

12
我当然不喜欢独角兽,但喜欢您的方法。谢谢。
Jonatas Walker 2015年

那改变globals.domain呢?
Fizzix

1
@iLoveUnicorns感谢您的回复。我将研究诸如“ express-session”之类的替代方法,因为我主要需要它来存储登录的用户数据。
Fizzix '16

11
我认为这是一种更好的方法,但它不会创建全局变量,也无法回答所提出的问题。这是一种替代方法,我会一直鼓励这样做,但是诸如“这是该线程上唯一的正确答案”之类的纯粹看涨的自大态度根本不属于这里。stackoverflow.com/help/be-nice
Thor84no,2016年

2
这可能是一种更好的方法,但是如果您尝试运行依赖全局名称空间中某些内容的外部创作脚本,那么这将无济于事。IOW,这不能回答问题。
宾基

12

像这样的全局名称空间呢? global.MYAPI = {}

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

在camilo-martin评论后进行编辑:所有其他海报都谈到所涉及的不良模式。因此,撇开这些讨论,全局定义变量的最佳方法(OP的问题)是通过名称空间。

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


3
require是为了什么!可以使用名称空间,但不要全部global.foo = global.foo || {}使用所有文件或其他内容。需要定义名称空间的文件。为孩子们做。
卡米洛·马丁

@ camilo-martin您好,1)通过定义global.MYAPI._,您无需在所有文件中都定义它,这就是成为全局文件的原因。2)这与孩子们无关。即使所有人都说这是错误的模式,也要取决于程序员和给定的情况,他如何使用这种语言的功能。
伊戈尔·帕拉

2
是的,但是假设您在单独的文件中声明了名称空间的某些功能。然后,您需要一个文件来使用该对象,该文件是向后的,并且也违反CommonJS和CommonSense。如果您需要使用东西,请让用户代码要求名称空间,而不要求名称空间。请注意,我并不是在针对名称空间说任何话,只是关于谁出于某种原因呼叫谁的约定。而且在客户端,您没有节点。请参阅您提到的链接以某种方式(通过全局)运行,因为它是关于浏览器而不是节点的。
卡米洛·马丁

1
遗憾的是,您发布的URL仅在不使用斜杠的情况下才有效;)
Dirigible

10

您可以只使用全局对象。

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

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

5

我同意,使用global / GLOBAL命名空间设置全局变量是不好的做法,并且从理论上讲,根本不使用它(理论上是可操作的词)。但是(是的,操作员)我确实使用它来设置自定义Error类:

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

global.MyError = [Function of MyError];

是的,这里是忌讳的,但是如果您的站点/项目在整个地方都使用自定义错误,则基本上需要在任何地方或至少在以下地方进行定义:

  1. 首先定义Error类
  2. 在您将其抛出的脚本中
  3. 在捕获它的脚本中

在全局命名空间中定义我的自定义错误可以免去需要我的客户错误库的麻烦。映像抛出未定义的自定义错误的自定义错误。

同样,如果这是错误的,请让我知道,因为我最近才刚刚开始这样做

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.