JS中的全局变量有害吗?

dhe*_*ein 1 javascript

根据这篇文章

http://www.mediaevent.de/javascript/globale-lokale-variablen.html

全局变量在JS中非常危险.

对不起,这是德语,但我要指出这篇文章的两个主要陈述.

第一个已经在头部声明的第2段.

它说"在JS全局变量中是危险的,因为它们可以被其他脚本加入名称"到目前为止很好,因为这主要是我想使用全局变量的方式不是吗?

但在文章中听起来这可能是随机发生的.那肯定不是预期的表现,是吗?

但更可怕的是第二句话.它预测如果多次调用声明全局变量的函数,将产生内存泄漏.但如果名称仍然相同,怎么会发生这种情况呢?如何将多个vars声明为全局同名?或者这篇文章可能是由一些人写的"半知识"?或者只是针对一些不习惯全球和本地之间差异的人?或者JS是否真的以这种方式行事?

现在是一个具体的例子:

我想要一些登录我的页面的人创建一个随机生成的令牌并通过单击登录来提交它.在另一个按钮上,我希望这个令牌由不同的函数访问,并且只是对它进行子提交,这样只有新的登录才能重新生成密钥.

对于那个键,我正在考虑使用一个全局变量,该变量由一个函数声明并由另一个函数返回.但是,由于我将生成/重新生成密钥可能超过一次,这会产生内存泄漏吗?或者这篇文章我指的可能只是戏剧化?如果这真的是JS的行为方式,那么在我的情况下,从一个不同的函数中获取变量的好方法是什么?

Ben*_*aum 7

全局变量的问题不是内存,而是性能.

全局变量的问题完全不同.问题是它们引入了全局状态,脚本没有绑定到命名空间.

让我们逐一解决这些问题.

拥有全球状态

这是最大的问题.编码需要模块依赖关系是明确的,并且代码片段之间的通信非常清楚.

当你有全局变量时,代码的一部分使用变量并不是那么清楚,你无法确定代码的哪个部分需要它,什么不需要.

假设我有一个Zoo项目,我有一项Bathe清理动物的服务.而不是传递Bathe给需要它的每只动物,我把它放在全局命名空间上,我只是打电话Bathe(myAnimal).

现在我想重组我的动物园,我想知道哪些动物需要洗澡,因为我想优化它.除了通过我的整个代码,我无法知道.为了看看我的长颈鹿是否需要洗澡,我必须阅读长颈鹿课程的全部代码.相反,如果我传递Bathe给长颈鹿的构造函数而不是使用它或在长颈鹿中创建它(一种称为依赖注入的概念),我可以看到长颈鹿只需阅读签名就需要洗澡.

现在这可能会变得更糟,如果我有状态怎么办?如果我实际上在多个位置更改全局变量,则跟踪变得非常困难.在多行代码库中,这意味着您可以全面更改状态,并且没有明确指示谁正在更改它.

这是主要的,你应该完全避免全局原因.

脚本未绑定到命名空间

如果我在页面上有两个脚本,并且我的第一个脚本A在全局命名空间上声明了一个变量,则第二个脚本可以访问该变量.这很有用,因为脚本可以通过这种方式进行交互,但它非常有害,因为它意味着脚本可以覆盖彼此的代码,并以不明确的方式进行通信.

这当然,如果你使用一个模块管理器,例如browserify或完全缓解RequireJS -这意味着你的整个脚本只公开了两个全局requiredefine再加载脚本通过加载器来完成.

这样就可以很好地定义独立的代码片段的交互方式.这并不妨碍您在全局对象上创建变量,但它有助于减少以统一方式执行此操作的需要.

关于安全的说明

当然,客户端上的任何东西都会受到损害,你不能在不安全的浏览器上做客户端JavaScript的安全性或类似的东西(也就是说,你没有阻止任何外部的东西),因为客户端只能运行任意代码在您的代码上阅读它.


Tib*_*bos 6

全局变量有三个大问题:

  1. 名称冲突
  2. 代码复杂性
  3. 垃圾收集

名称冲突

在全局范围内使用变量的问题在于,您对该范围内的其他内容的控制较少.您的代码全局使用ga_变量并且工作正常,但是当您添加使用相同变量的Google Analytics代码段时,意外失败并且很难看出为什么您的购物车在3个页面加载中失败了.

如果您可以将代码包装在IIFE中以防止在全局范围内有任何变量,那么您应该这样做.显然,在某些情况下,您确实希望全局访问您的代码(例如:jQuery库).在这些情况下,最佳做法是将所有内容保存在具有相关名称的单个命名空间(jQuery)中.

代码复杂性

对代码进行分区通常是个好主意,这样各个部分之间的交互最少.交互越多,就越难以进行更改并追踪错误的来源.显然,可以在任何地方访问全局变量,因此当您遇到某些访问全局变量的代码时,您必须检查该变量的每个用法,这可能是一个非常大的痛苦.要避免这些痛苦的事情是将变量保持为本地变量并封装代码片段,这样除非通过特定接口,否则它们不能相互交互.

内存泄漏

在JavaScript中,您几乎无法控制垃圾收集过程.所有保证的是,如果您可以访问变量,它将不会被垃圾收集.这意味着如果您想要收集垃圾,那么您必须确保无法再访问它.虽然i保持数字的全局变量不会有什么大不了的,正如@Boluc Papuaccoglu提到的那样,当你的全局变量随着时间的推移保持越来越多的属性(例如XHR请求数组或创建的DOM对象数组)时,内存消耗变成了一个大问题.

所有这些情况都是最糟糕的情况,您可能不会遇到小应用程序的问题.当你开始学习编程时,这些建议最有价值,因为他们养成了良好的习惯,当你在复杂的应用程序上工作时,他们可以省去你在调试上浪费的时间和金钱,或者很难做到改进.