【问题标题】:Node.js global variablesNode.js 全局变量
【发布时间】:2011-07-23 19:07:20
【问题描述】:

我在这里问: Does Node.js require inheritance?

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

这对我不起作用。

也就是说,以下内容不会使 _ 在所需文件上可用。

_ = require('underscore');

我可以使用 Express.js 的 app.set 进行设置,但可以在其他地方使用。

这应该是这样工作的吗?

【问题讨论】:

  • 上面这行哪里来的?
  • 我认为如果您对上一个问题的回答不起作用,您不应该开始一个新问题。而是在那里添加评论并删除接受的标签。
  • 只需对其进行编辑,它就会出现在当前活动的问题列表中。
  • 使用exports。好多了。
  • 也许它不起作用,因为你有“使用严格”;在文件的顶部。对我来说就是这样。

标签: javascript node.js express


【解决方案1】:

当项目变得更大时,使用 GLOBAL 关键字的其他解决方案是维护/可读性(+命名空间污染和错误)的噩梦。我已经多次看到这个错误并且很难修复它。

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

示例:

文件 globals.js

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

module.exports = Globals;

如果你想使用这些,请使用 require

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

【讨论】:

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

使用像global.MYAPI = {}这样的全局命名空间:

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

所有其他海报都谈到了所涉及的不良模式。因此,撇开讨论不谈,全局定义变量的最佳方法(OP 的问题)是通过命名空间。

提示:Development Using Namespaces

【讨论】:

  • 这就是require 的用途!可以使用命名空间,但不要在所有文件上全部使用 global.foo = global.foo || {} 或其他东西。需要定义命名空间的文件。为孩子们做这件事。
  • @camilo-martin 嗨,1)通过定义 global.MYAPI._ 你不需要在所有文件中定义它,这就是全局的原因。 2)这与孩子无关。即使所有人都说这是不好的模式,这取决于程序员和给定情况他如何使用语言的这种能力。
  • 是的,但是假设您在单独的文件中声明了命名空间的一些功能。然后你需要一个文件来使用该对象,这也是倒退的,也违背了 CommonJS 和 CommonSense。如果你需要一些东西,让用户代码需要命名空间,而不是命名空间所需要的。请注意,我并不是在说任何反对 命名空间的内容,只是有关于谁调用谁的约定是有原因的。在客户端,您没有节点拥有的东西;看到你提到的链接以某种方式(通过全局)做事,因为它是关于浏览器而不是节点。
  • 遗憾的是,您发布的网址仅在您省略尾部斜杠时才有效;)
【解决方案3】:

我同意使用 global/GLOBAL 命名空间来设置任何全局是不好的做法,并且在理论上根本不要使用它(理论上是有效的词)。但是(是的,操作员)我确实使用它来设置自定义错误类:

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

global.MyError = [Function of MyError];

是的,这是禁忌,但如果您的站点/项目在整个地方都使用自定义错误,您基本上需要在任何地方定义它,或者至少在某个地方:

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

在全局命名空间中定义我的自定义错误为我省去了 require'ing 我的客户错误库的麻烦。在未定义自定义错误的情况下,成像会引发自定义错误。

【讨论】:

    【解决方案4】:

    在 Node.js 中,您可以通过“global”或“GLOBAL”对象设置全局变量:

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

    或者更有用...

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

    从 Node.js 源代码中,您可以看到它们之间存在别名:

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

    在上面的代码中,“this”是全局上下文。使用CommonJS 模块系统(Node.js 使用),模块内的“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');。是的,您在每个使用 Underscore.js 的文件中都这样做,就像在 Java 中所做的 import com.foo.bar; 一样。由于文件之间的链接是“显式”的,因此更容易弄清楚您的代码在做什么。这有点烦人,但这是一件好事。 ....这就是讲道。

    每条规则都有一个例外。我正好有一个实例,我需要在其中设置“GLOBAL._”。我正在创建一个用于定义“配置”文件的系统,这些文件基本上是 JSON,但“用 JavaScript 编写”以提供更多的灵活性。此类配置文件没有“要求”语句,但我希望它们能够访问 Underscore.js(整个系统基于 Underscore.js 和 Underscore.js 模板),因此在评估“配置”,我会设置“GLOBAL._”。所以,是的,对于每条规则,都有一个例外。但你最好有一个很好的理由,而不仅仅是“我厌倦了输入 'require',所以我想打破惯例”。

    【讨论】:

    • 使用 GLOBAL 的缺点是什么?为什么我需要一个很好的理由?最重要的是我的应用可以正常工作,对吧?
    • 最终,是的,如果您发货,这才是最重要的。但是,某些实践被称为“最佳实践”,遵循它们通常会增加您运输和/或能够维护您所构建的东西的几率。遵循“良好实践”的重要性随着项目的规模和寿命的延长而增加。我已经在短命的项目中构建了各种讨厌的技巧,这些项目是一次写入、从不读取(和“单一开发人员”)。在一个更大的项目中,这种偷工减料最终会让你失去项目动力。
    • 具体来说,对于 GLOBAL,问题在于可读性。如果你的程序乱用全局变量,就意味着要想看懂代码,就必须了解整个app的动态运行时状态。这就是程序员对全局变量持谨慎态度的原因。我敢肯定有几十种方法可以有效地使用它们,但我们大多只是看到初级程序员滥用它们导致产品的弊端。
    • 为什么你不能把你的配置放在一个普通的.js 文件中并在导出配置之前调用require
    • @Jackie - en.wikipedia.org/wiki/Singleton_pattern。如果你正在做的事情映射到单例模式,那么它可能是有意义的。在以下情况下,数据库连接可以是单例的:1)设置成本很高,2)您只希望连接设置一次,3)连接对象是长期存在的,并且在网络中断时不会进入失败状态, 4) 连接对象是线程安全的/能够被许多不同的调用者共享。
    【解决方案5】:

    你可以像这样使用global

    global._ = require('underscore')
    

    【讨论】:

    • 您能否提供更多信息?这是javascript的一部分还是节点的一部分?这是一个很好的模式吗?就像我应该这样做还是应该使用 express set?谢谢
    • 前面的评论有误。在浏览器中,window 是全局对象。 documentwindow 的属性。
    • 这不是一个好的模式。不要这样做。使用“require”来解耦模块的约定是经过深思熟虑的。没有充分的理由,你不应该违反它。请参阅下面的回复。
    • 全局变量通常是要避免的,但如果你真的想使用它们。下面的 3 条语句都是等效的,并将分配一个 var 到全局范围: GLOBAL._ = require('underscore'); global._ = require('下划线'); _ = 要求('下划线');
    • 当您的项目开始变得更大时,这将成为维护的噩梦。请看看我的方法。
    【解决方案6】:

    你可以只使用全局对象。

    var X = ['a', 'b', 'c'];
    global.x = X;
    
    console.log(x);
    //['a', 'b', 'c']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 2011-05-07
      相关资源
      最近更新 更多