JS中的全局变量有害吗?

时间:2013-10-11 08:06:15

标签: javascript

根据这篇文章

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

JS中的全局变量非常危险。

我很抱歉这是德语,但我要指出这篇文章的两个主要陈述。

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

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

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

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

现在是一个具体的例子:

我想要一些登录我页面的人创建一个随机生成的令牌并通过点击登录来提交。 在另一个按钮上,我希望这个令牌由另一个函数访问,并且只是将它提交给它,这样只需要为新登录重新生成密钥。

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

3 个答案:

答案 0 :(得分:7)

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

全局变量的问题完全不同。问题在于它们引入了全局状态,并且脚本未绑定到命名空间

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

拥有全球状态

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

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

假设我有一个Zoo项目,我有Bathe服务来清理动物。不是将Bathe传递给需要它的每只动物,而是将它放在全局命名空间中,我只需要调用Bathe(myAnimal)

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

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

这是你应该完全避免使用全局变量的主要原因。

脚本未绑定到命名空间

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

如果您使用像browserify或RequireJS这样的模块加载器,这当然可以完全缓解这意味着您的整个脚本只暴露两个全局变量 - requiredefine然后完成脚本加载通过装载机。

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

关于安全性的说明

当然,客户端上的任何内容都会受到损害,您无法在不安全的浏览器上的客户端JavaScript中执行安全性或类似的操作(也就是说,您没有阻止任何外部操作)因为客户端可以只是在代码上运行任意代码并阅读它。

答案 1 :(得分:6)

全局变量存在三个大问题:

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

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

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

    代码复杂性

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

    内存泄漏

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

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

答案 2 :(得分:0)

关于内存泄漏:假设您有一个函数,并在其中定义var,并将其用于某种目的,然后从函数返回。在这种情况下,将释放变量使用的内存。但是,如果您依赖全局变量来执行相同的操作,那么在函数退出后很长时间内将继续分配内存。扩展相同的场景,假设您的函数为此变量添加属性,其名称取决于函数正在处理的数据(如订单ID,客户名称等)。现在,每次调用函数时,越来越多的属性将被附加到这个变量,它会成长和增长。