javascript 为什么全局变量被认为是不好的做法?

sbdsn5lh  于 2023-02-15  发布在  Java
关注(0)|答案(9)|浏览(134)

我不断看到警告不要在JavaScript中使用全局变量,但似乎人们这么说的唯一原因是因为全局变量阻塞了全局名称空间。我可以想象,通过将所有变量放入一个大对象中,可以很容易地解决这个问题。现在的问题是:除了方便之外,还有其他原因不使用全局变量吗?2是否有任何性能或兼容性问题涉及到全局变量?

vh0rcniy

vh0rcniy1#

它们使全局名称空间变得混乱,并且查找速度比局部变量慢。
首先,有很多全局变量总是一件坏事,因为很容易忘记你在某个地方声明了一个变量,然后意外地在其他地方重新声明了它。如果你的第一个变量是局部变量,那么你就没有问题。如果它是全局变量,然后它就被覆盖了。当你使用隐式全局变量时,情况会变得更糟(例如,当您说someVar = someValue而没有使用var关键字声明someVar时)。
其次,全局变量比局部变量需要更长的时间来被Javascript“找到”。速度上的差异不是很大,但它确实存在。
要进一步阅读并更深入地解释为什么全局变量被认为是不好的做法,您可能需要查看this page

6fe3ivhb

6fe3ivhb2#

全局变量会显著增加耦合性,显著降低代码的可伸缩性和可测试性。一旦你开始使用全局变量,你现在必须知道变量在哪里以及如何被修改(例如,破坏封装)。大多数文献和惯例都认为,在使用全局变量时,性能是你最不关心的问题。
这是一个fantastic article outlining why全局变量引起的头痛问题。

iyfamqjs

iyfamqjs3#

总而言之,全局变量会导致(以及更多)以下问题。
1)变量命名冲突--如果你在一个团队中工作,你和你的同事在全局范围内使用相同的变量名,最后定义的变量将覆盖初始变量。这显然会带来灾难性的后果。
2)安全性-特别是在网络上,每个用户都可以访问Window(或全局)对象。通过将变量放在全局作用域中,任何用户都可以查看或更改变量。
3)慢--这可以说是微不足道的,但它仍然存在。JavaScript变量查找的工作方式是JavaScript引擎将在当前查找变量的作用域中查找。如果找不到,它将在下一个父作用域中查找。如果在那里找不到,它将继续向上查找直到到达全局对象寻找那个变量.如果你所有的变量都位于全局作用域,JavaScript引擎将总是必须遍历每个作用域以便最终到达全局作用域来找到变量。

raogr8fs

raogr8fs4#

如果你的脚本很长,并且你使用了很多函数中的变量,这会增加你的调试时间,因为全局变量的值可能在任何地方被改变,所以如果你要跟踪哪里改变成了一个非预期的值,你必须检查所有变量。
如果不同的程序员从页面中包含的其他脚本修改此变量,则这种情况会更加痛苦。

46qrfjad

46qrfjad5#

在你的代码中使用全局变量应该没有任何问题,只要你把它们 Package 在一个唯一的命名空间/对象中(以避免与不属于你的脚本冲突)
在javascript中使用全局变量有一个优点,它源于javascript不是一种强类型语言的事实。因此,如果你把一些复杂的对象作为参数传递给一个函数,你可能会失去这些对象的所有智能(在函数作用域中)。当使用全局对象代替时,将保留智能。当您具有智能时,它实际上可以提高调试时间(与别人所说的相反...)
我个人觉得这非常有用,它当然在我的代码中占有一席之地。
(of当然,我们应该始终在局部变量和全局变量之间取得正确的平衡)

nwsw7zdq

nwsw7zdq6#

基本上,因为它们可以从页面上的任何脚本访问,并且因为你可以在相同的作用域中重复它的名称。这就是为什么很多Javascript引擎使用下面的代码:

(function(){
    var foo = 'foo',//Local
    bar = 'bar';//Local
    window.globalVar = foo + bar;//Global
})();
alert(foo);//Error
alert(bar);//Error
alert(globalVar );//'foobar'
9wbgstp7

9wbgstp77#

您创建的全局变量可能会覆盖现有的窗口对象属性。因为全局变量是在全局上下文中访问的,即窗口对象。

qxgroojn

qxgroojn8#

一般来说,我们应该将相似的代码和变量组合在一起,并在它们周围竖起栅栏。这被称为类,它确实有助于组织程序。良好的组织使其他人更容易阅读您的代码,更容易随着程序的增长维护代码,更容易编写单元测试,更容易重用代码并避免代码重复。
当从只有一个维护人员的小程序跳转到有多个人参与的中型或大型程序时,所有这些都是必不可少的。
全局变量周围没有围栏,也不与任何其他代码组合在一起。它们可能会影响程序的任何其他部分,而且很难一眼看出它们会影响哪些部分。全局变量需要在单元测试中被模拟,而且仅仅通过查看方法定义,一眼还不清楚它们是否需要被模拟。

jgwigjjp

jgwigjjp9#

在使用全局变量的JavaScript中添加另一个全局危险,它们最终可能隐藏标准API。

var focus = false;

const elem = document.querySelector('#name');
elem.addEventListener('focus', _ => { focus = true; show(); });
elem.addEventListener('blur', _ => { focus = false; show(); });

function show() { console.log('focus:', focus); }
<input id="name" type="text">

在上面的代码中,我创建了一个名为focus的全局变量,但是它覆盖了the focus function on window。我可能会在以后包含一个调用window.focus的库,但是它会失败。
window会不时地添加新的函数和属性,所以以后您可能会命名一些与浏览器冲突的内容。
类似地,我见过(并编写过)这样的代码😅) code like this

if (!window.MyAPI) {
  window.MyAPI = ...
}

...
MyAPI.doTheThing();

或者简称

window.MyAPI = window.MyAPI || ...

...
MyAPI.doTheThing();

这种特殊模式的问题是浏览器可能会发布一个名为MyAPI的新API,在这种情况下,检查不会替换全局,doTheThing也不会存在。
Reporting API就是这样一个问题,一个非常流行的库有一个名为Report的类或函数,它试图像上面那样有条件地全局安装,当浏览器试图发布Reporting API时,每个使用该库的站点都崩溃了。
有两种解决方案。
1.(差),不条件分配全局

window.MyAPI = window.MyAPI || ...  // bad!
window.MyAPI = ...                  // still bad but better

在这种情况下,你至少要用你自己的API覆盖新的浏览器API。当然,现在你有一个问题,一些其他的库可能想使用新的API,你已经有效地隐藏了它。
1.(好),不要使用全局变量。
上面的模式可以说是es6之前模块时代遗留下来的,现在可以说是把你的库放在一个模块中更好。
然后,您可以将其导入到局部变量或至少模块级变量中

import MyAPI from './MyAPI.js';

MyAPI.doTheThing()

注意:最后一个示例中的MyAPI是也不是全局变量。它只能由当前模块访问,因此它对该模块是全局变量,而对其他模块不是。
注2:上述建议的一个例外是标准库的多边形填充。
注3:如果不清楚,JavaScript中的global会被赋值为全局对象的属性,在浏览器中是window。此外,添加到全局对象的属性也会成为全局对象。
示例:

console.log('foo' in window);  // prints false
console.log('foo' in window);  // prints true
var foo = 123;

window.bar = 456;
console.log(bar);  // prints 456

相关问题