node.js全局变量?

Har*_*rry 203 javascript node.js express

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

并被告知我可以通过省略var来将变量设置为全局范围.

这对我不起作用.

即:

_ = require('underscore');
Run Code Online (Sandbox Code Playgroud)

不能使_在所需文件上可用.我可以设置快递,app.set并在其他地方提供它.

有人可以确认这应该有用吗?谢谢.

mas*_*lum 228

global._ = require('underscore')

  • 这不是一个好的模式.不要这样做.使用'require'来解耦模块的惯例经过深思熟虑.如果没有充分理由,你不应该违反它.请参阅下面的回复. (75认同)
  • 你能提供更多信息吗?这是javascript的一部分还是节点的一部分?这是一个好的模式吗?我应该这样做,还是应该使用快递?谢谢 (23认同)
  • 之前的评论不正确.在浏览器中,`window`是全局对象.`document`是`window`的属性. (4认同)

Dav*_*son 216

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

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

或更有用......

GLOBAL.window = GLOBAL;  // like in the browser
Run Code Online (Sandbox Code Playgroud)

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

node-v0.6.6/src/node.js:
28:     global = this;
128:    global.GLOBAL = global;
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,"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: {} }
*/
Run Code Online (Sandbox Code Playgroud)

**注意:关于设置"GLOBAL._",一般情况下你应该这样做var _ = require('underscore');.是的,你在使用下划线的每个文件中都这样做,就像你在Java中一样import com.foo.bar;.这样可以更容易地弄清楚代码的作用,因为文件之间的链接是"显式的".轻微烦人,但好事.......这就是讲道.

每条规则都有例外.我恰好有一个实例,我需要设置"GLOBAL._".我正在创建一个用于定义"配置"文件的系统,这些文件基本上是JSON,但是"用JS编写"以允许更多的灵活性.这样的配置文件没有'require'语句,但是我希望它们能够访问下划线(整个系统是以下划线和下划线模板为基础的),所以在评估"config"之前,我会设置"GLOBAL._".所以是的,对于每一条规则,某处都有例外.但你最好有一个很好的理由而不仅仅是"我厌倦了打字'需要'所以我想打破常规".

  • 具体来说,对于GLOBAL,问题在于可读性.如果您的程序滥用全局变量,则意味着为了理解代码,我必须了解整个应用程序的动态运行时状态.这就是程序员对全局变量持怀疑态度的原因.我确信有几种方法可以有效地使用它们,但我们大多只是看到它们被初级程序员滥用到产品的病态. (47认同)
  • 最终,是的,如果你发货,这就是最重要的.但是,某些做法被称为"最佳做法",跟随它们通常会增加您的运输和/或能够维持您所建造的内容的几率.遵循"良好实践"的重要性随着项目的规模而增加,并且它的寿命也很长.我已经将各种讨厌的黑客构建成了一次性写入,从不读取(和"单一开发人员")的短期项目.在一个更大的项目中,这种角落切割最终会导致您投射动力. (24认同)
  • 使用GLOBAL有什么不足之处?为什么我需要一个很好的理由?底线是我的应用程序工作,对吧? (7认同)
  • @Jackie - https://en.wikipedia.org/wiki/Singleton_pattern.如果你正在做的事情映射到Singleton模式,那么它可能是有意义的.在以下情况下,数据库连接可以是单例:1)设置很昂贵; 2)您只希望连接设置一次,3)连接对象是长期存在的,并且在网络打嗝的情况下不会进入失败状态, 4)连接对象是线程安全的/能够由许多不同的呼叫者共享. (3认同)
  • 你为什么不能把你的配置放在常规的`.js`文件中并在导出配置之前调用`require`? (2认同)

Oli*_*xon 74

当项目变大时,使用GLOBAL关键字的其他解决方案是维护/可读性(+命名空间污染和错误)的噩梦.我多次看到这个错误并且有解决它的麻烦.

使用JS文件然后使用模块导出.

例:

globals.js

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

module.exports = Globals;
Run Code Online (Sandbox Code Playgroud)

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

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.
Run Code Online (Sandbox Code Playgroud)

  • 我当然不喜欢独角兽,但喜欢你的方法.谢谢. (11认同)
  • 虽然我认为这是一种更好的方法,但它不会创建全局变量并且不会回答所提出的问题.这是一种替代方法,我总是鼓励那些,但是像"这是这个线程上唯一正确的答案"这样的陈述的纯粹看涨自大,根本就不属于这里.http://stackoverflow.com/help/be-nice (10认同)
  • @iLoveUnicorns 感谢您的回复。我将研究“express-session”等替代方案,因为我主要需要它来存储登录的用户数据。 (2认同)
  • 这可能是一种更好的方法,但如果您尝试运行外部创作的脚本,这些脚本依赖于全局命名空间中的某些内容,这对您没有帮助.IOW,这不回答这个问题. (2认同)

Igo*_*rra 12

怎么样的全局命名空间 global.MYAPI = {}

global.MYAPI._ = require('underscore')
Run Code Online (Sandbox Code Playgroud)

在camilo-martin评论之后编辑:所有其他海报都谈到了涉及的坏模式.因此,抛开讨论,全局定义变量(OP的问题)的最佳方法是通过名称空间.

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

  • 这就是`require`的意思!可以使用命名空间,但不要全部使用`global.foo = global.foo || {}`对所有文件或其他东西.需要定义命名空间的文件.为孩子们做. (3认同)
  • 是的,但是假设您在单独的文件中声明了命名空间的一些功能.然后,您需要一个文件来使用该对象,该对象也是向后的,并且也违反了CommonJS和CommonSense.如果您需要填充内容,请让用户代码需要命名空间,而命名空间不需要.注意我没有对任何**命名空间说什么*,只是因为某些原因而调用谁的惯例.在客户端,你没有什么节点; 看到你提到的链接是以某种方式(通过全局)做事,因为它是关于浏览器而不是节点. (2认同)

Joa*_*cao 9

您可以只使用全局对象.

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

console.log(x);
//['a', 'b', 'c']
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

global.MyError = [Function of MyError];
Run Code Online (Sandbox Code Playgroud)

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

  1. 首先定义Error类
  2. 在脚本中
  3. 在捕获它的脚本中

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

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