node.js 标准模块的全局变量?

Posted

技术标签:

【中文标题】node.js 标准模块的全局变量?【英文标题】:Global variables for node.js standard modules? 【发布时间】:2011-05-07 15:22:59 【问题描述】:

我知道全局变量不好。

但是,如果我在我的框架中的 40 个文件中使用节点的模块“util”,那么将其声明为全局变量不是更好吗:

util = require('util');

在 index.js 文件中而不是在 40 个文件中写入该行?

因为我经常在每个文件中使用相同的 5-10 个模块,这样可以节省大量时间,而不是一直复制粘贴。

在这种情况下,DRY 不是很好吗?

【问题讨论】:

仅供参考使用global(小写)而不是GLOBAL(大写)每node's deprecation warning 【参考方案1】:

你可以只拥有一个通用模块。

common.js:

Common = 
  util: require('util'),
  fs:   require('fs'),
  path: require('path')
;

module.exports = Common;

app.js:

var Common = require('./common.js');
console.log(Common.util.inspect(Common));

【讨论】:

这是个好主意。事实上,由于 require 的 exports 对象已被缓存,因此在读取未使用的 requires 文件时不会产生额外成本。 (您可以通过在common.js 中添加console.log 行来测试它是否已缓存,并注意无论您需要多少次,console.log 只会在第一次发生。) 我不明白为什么这比每个模块上的 require(...) 更好,因为它被缓存了?有什么区别? @Kato:这更好(实际上很棒),因为您现在不必在每个文件中包含 10 个模块,而只需一个。正如你所说,它们被缓存了,所以这样做绝对不会过热。 1.这会产生不必要的依赖。 2. 它节省了很少的内容或创建了更多的输入,因为现在你要么有“Common.x.whatever”,而不仅仅是“x.whatever”,每个你使用“whatever”的地方,或者你用“var x = Common.x”作为别名就像 "var x = require(...)" 但如果你还不知道 "x" 是什么就不太清楚。 3. "x" 的重构用法现在强制搜索 Common.x 和 require("x"),因为你不能确定每个人都使用过 Common.x。如果你经常使用它,为什么不直接做一个 sn-p "rutil > tab"? @user170934 1. 没必要。 2. 它省去了很多关于循环依赖和思考每个文件需要什么的时间的麻烦,同时提供了一个在整个项目中使用的清晰的命名空间。 let x = common.x 也比 x = require() 语句的许多行干净得多。【参考方案2】:

每个模块都应该是独立的。在每个模块的第一个之后,require 无论如何都不会花费任何费用。

如果您想单独测试一个模块怎么办?您会遇到很多问题,因为它无法识别您的应用中的某些“全局”要求。

是的,全局变量很糟糕,即使在这种情况下也是如此。全局变量几乎总是毁掉:可测试性、封装性和易维护性。

2012 年 1 月更新答案

global 对象现在是每个模块内的全局对象。所以每次你分配给模块内的一个全局变量(无作用域)时,它都会成为该模块的global 对象的一部分。

global 对象因此仍然不是全局,因此不能这样使用。

2012 年 12 月更新

global 对象现在在应用程序内具有全局范围,可用于存储需要从所有模块访问的任何数据/函数。

【讨论】:

@RadagasttheBrown 好吧,您还应该考虑该节点不支持用户制作的全局变量。 用户制作的全局变量?你能详细说明一下吗? @TorValamo 这似乎不正确,我刚刚做了一个测试。在一个模块中分配给global.something 的任何内容都可以从另一个模块访问。所以global 持有进程(=应用程序)全局变量,而不是模块全局变量,global 是所有会话的同一个对象。至少这对我来说是这样的。我能问你为什么说global 是模块的本地吗?您是否进行了测试,如果是,那么测试是什么? @TorValamo 确实有点令人困惑。他们只用了 1 行来说明 global 是什么,不解释它是如何工作的,然后用 3 行来咆哮为什么需要它。仍然here 他们说:“这些对象在所有模块中都可用。其中一些对象实际上不在全局范围内,而是在模块范围内......”并且here:“全局:Object 全局命名空间对象。” ...无论如何,案件已结案,是时候再次更新答案了:)你会还是我应该? @esp 随时更新它,你似乎比我有更多关于它的最新信息;)【参考方案3】:
global.util = require('util');

node documentation 中有一个关于全局对象的部分。

但是,应谨慎使用全局变量。通过将模块添加到全局空间,您会降低可测试性和封装性。但在某些情况下,使用这种方法是可以接受的。例如,我将函数和对象添加到全局命名空间以在我的单元测试脚本中使用。

【讨论】:

全局对象与全局范围不同。你的任务基本上分配给虚无。 @Kato - 在 node.js 中,全局对象不是您可以编写脚本的实际对象。它是 node.js 引擎中的一个内部对象。如果要专门使用全局变量,则应使用process,相当于浏览器中的window。 (尽管该过程不包含setTimeout 和其他“全局变量”,因为它们本身就是全局对象)。【参考方案4】:

我对这个帖子中的答案感到困惑。

我能做到……

文件:test.js

global.mytest = 
    x: 3,
    y: function()  console.log('Works.'); 
;

文件:test2.js

console.log('Does this work?');
mytest.y();

文件:server.js

require('test.js');
require('test2.js');

它似乎可以根据需要解决问题。第一个 require 将 mytest 对象放入全局范围,然后第二个 require 可以访问该对象而无需任何其他限定符。

我试图弄清楚这一点(它把我从谷歌搜索带到了这个线程),我想发布现在似乎对我有用的东西。也许自从最初的答案以来事情已经发生了变化。

【讨论】:

是的,最近的 Node.js 版本确实改变了这一点。 (虽然“最近”是相对而言;那个版本的 Node 现在已经相当老了。)【参考方案5】:

我已经成功地使用process 对象来传递我的配置对象。虽然理论上存在与上述完全相同的问题(封装、可测试性等),但它在仅使用非状态修改属性(基本上是带有原语的哈希表)时可以正常工作。

【讨论】:

你能分享一些文章,解释什么是封装和可测试性【参考方案6】:

如果您将模块包装在块中(例如匿名函数),您可以绑定到本地名称(通过参数或 'var'),然后使用您想要的任意长(可能是“包”标签)名称(如果您甚至此时需要一个全局变量)。

例如,我的模块通常看起来类似于:

;(function ($, $exp, other) 
  $(...)
  other.xyz()
  $exp.MyExportedObject = ...;
)(jQuery, window, some_module.other_expression) // end module

我使用带有 noConflict 的 jQuery,这是前者,而后者表明您可以对任何表达式执行此操作——全局、要求、计算、内联等……同样的“包装”方法可用于消除所有(或几乎所有)“特殊命名的”全局变量——全局变量必须存在于某个级别,但是,消除潜在的冲突是一个非常大的胜利。

【讨论】:

这是关于 node.js 而不是 jquery

以上是关于node.js 标准模块的全局变量?的主要内容,如果未能解决你的问题,请参考以下文章

node.js中的全局变量——global

node.js中的全局变量——global

Node.js 概述

node.js的基本语法

在“模块”全局变量上运行 grunt-typescript 时,angular-mock 和 node.js 发生冲突

Node. js 有哪些全局对象?