Node.js 全局变量

IT技术 javascript node.js express
2021-01-12 14:18:42

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

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

这对我不起作用。

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

_ = require('underscore');

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

这是应该的工作方式吗?

6个回答

你可以global像这样使用

global._ = require('underscore')
全局变量通常是要避免的,但如果你真的想使用它们。下面的 3 条语句都是等价的,并且会为全局范围分配一个 var: GLOBAL._ = require('underscore'); global._ = require('下划线'); _ = require('下划线');
2021-03-16 14:18:42
这不是一个好的模式。不要这样做。使用“require”来解耦module的约定是经过深思熟虑的。没有充分的理由,你不应该违反它。看我下面的回复。
2021-03-18 14:18:42
你能提供更多的信息吗?这是javascript的一部分还是节点的一部分?这是一个很好的模式吗?我应该这样做还是应该使用快速集?谢谢
2021-03-21 14:18:42
之前的评论是错误的。在浏览器中,window是全局对象。document是 的属性window
2021-03-25 14:18:42
当您的项目开始变得更大时,这将成为维护的噩梦。请看一下我的方法。
2021-04-08 14:18:42

在 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”是全局上下文。使用CommonJSmodule系统(Node.js 使用的),module内的“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 编写”以提供更大的灵活性。这样的配置文件没有'require'语句,但我希望它们能够访问Underscore.js(整个系统基于Underscore.js和Underscore.js模板),所以在评估“配置”之前,我会设置“全球的。_”。所以是的,对于每个规则,某处都有一个例外。但是你最好有一个很好的理由,而不仅仅是“我厌倦了输入'require',所以我想打破惯例”。

使用 GLOBAL 的缺点是什么?为什么我需要一个该死的好理由?最重要的是我的应用程序可以工作,对吗?
2021-03-14 14:18:42
@Jackie - en.wikipedia.org/wiki/Singleton_pattern如果你正在做的事情映射到单例模式,那么它可能是有意义的。在以下情况下,DB 连接可以是单例的:1) 设置成本高,2) 您只想建立一次连接,3) 连接对象是长期存在的,并且在网络出现故障时不会进入失败状态, 4)连接对象是线程安全的/能够被许多不同的调用者共享。
2021-03-19 14:18:42
具体来说,对于 GLOBAL,问题是可读性之一。如果你的程序混杂使用全局变量,那就意味着为了理解代码,我必须理解整个应用程序的动态运行时状态。这就是程序员对全局变量持谨慎态度的原因。我确信有很多方法可以有效地使用它们,但我们大多只是看到初级程序员滥用它们导致产品出现问题。
2021-04-02 14:18:42
为什么不能将配置放在常规.js文件中并require在导出配置之前调用
2021-04-03 14:18:42
最终,是的,如果您发货,那就是最重要的。但是,某些实践被称为“最佳实践”,遵循它们通常会增加您的运输和/或能够维护您所构建的东西的几率。遵循“良好实践”的重要性随着项目的规模和寿命的增加而增加。我已经在短期项目中构建了各种讨厌的黑客,这些项目是一次写入,从不读取(和“单一开发人员”)。在一个更大的项目中,这种切角最终会消耗你的项目动力。
2021-04-09 14:18:42

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

使用 JavaScript 文件,然后使用module导出。

例子:

文件globals.js

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

module.exports = Globals;

然后,如果您想使用这些,请使用require

var globals = require('globals'); // << globals.js path
globals.domain // << Domain.
globals.domain了又怎样?
2021-03-26 14:18:42
我当然不喜欢 Unicorns,但喜欢你的方法。谢谢。
2021-03-30 14:18:42
@iLoveUnicorns 感谢您的回复。我将研究诸如“express-session”之类的替代方案,因为我主要需要它来存储登录的用户数据。
2021-03-30 14:18:42
虽然在我看来这是一种更好的方法,但它不会创建全局变量,也不会回答所提出的问题。这是另一种方法,我总是鼓励这些方法,但是诸如“这是该线程上唯一正确的答案”之类的纯粹看涨自大的说法根本不属于这里。stackoverflow.com/help/be-nice
2021-04-05 14:18:42
这可能是一种更好的方法,但是如果您尝试运行依赖于全局命名空间中某些内容的外部编写的脚本,这对您没有帮助。IOW,这不能回答问题。
2021-04-05 14:18:42

使用全局命名空间,如global.MYAPI = {}

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

所有其他海报都在谈论所涉及的不良模式。因此,将讨论放在一边,全局定义变量的最佳方法(OP 的问题)是通过名称空间。

提示:使用命名空间进行开发

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

您可以只使用全局对象。

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

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