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 标准模块的全局变量?的主要内容,如果未能解决你的问题,请参考以下文章