Javascript 为什么闭包比全局变量更好地保存变量?

Javascript 为什么闭包比全局变量更好地保存变量?,javascript,closures,Javascript,Closures,我理解闭包在JavaScript中是如何工作的,但我的问题是,为什么要费尽心机创建闭包来保存变量?你不能把变量设为全局变量吗?或者,这会扰乱全局范围,使您的代码容易出错。原因之一是防止全球污染。另一种方法是对许多操作使用相同的实现,只需更改传递的值即可 js> makeadd = function(num) { return function(val) { return num+val } } function (num) { return function (val) {retu

我理解闭包在JavaScript中是如何工作的,但我的问题是,为什么要费尽心机创建闭包来保存变量?你不能把变量设为全局变量吗?或者,这会扰乱全局范围,使您的代码容易出错。

原因之一是防止全球污染。另一种方法是对许多操作使用相同的实现,只需更改传递的值即可

js> makeadd = function(num) { return function(val) { return num+val } }
function (num) {
    return function (val) {return num + val;};
}
js> add3 = makeadd(3)
function (val) {
    return num + val;
}
js> add4 = makeadd(4)
function (val) {
    return num + val;
}
js> add3(add4(2))
9

这是一个范围问题。全局变量就是:全局的,对每个人来说。通过闭包,可以更好地控制变量的范围(可见性),这意味着可以更好地控制可能的意外副作用

[Globals]通常被认为是不好的做法,正是因为它们的非局部性:一个全局的 变量可以从任何地方修改(除非它们位于受保护的内存中), 程序的任何部分都可能依赖于它。因此,全局变量具有 创建相互依赖关系和添加相互依赖关系的无限潜力 增加了复杂性。看


JavaScript中只有一个全局名称空间,因此在同一页面上使用不同的框架/工具包是非常困难的,因为变量名迟早会发生冲突

闭包还提供了一种模拟私有变量的方法:

function Counter(start) {
   var count = start;
   return {
       increment: function() {
           count++;
       },

       get: function() {
           return count; // only gives you the value, but no write access
       }
   }
}
但这是一个相当“愚蠢”的例子,闭包在处理各种回调时特别有用,您不想管理保存每个回调数据的全局数组,闭包非常简单,而且更干净

要了解闭包的极端用法,请查看JavaScript类。(免责声明,代码是我写的。)


在这里,
proto
跟踪每个类的原始属性,但它仍然可以用于
extend
,当这些属性从其他类继承时,它可以将这些属性添加到其他类中。

其他人都已经提到了golbal名称污染,甚至OP:

还是会把全球范围搞得乱七八糟

但还有一个原因

全局变量只有一个实例。这使得它不能很好地扩展。如果在将来的某个时候,您需要多个对象实例,则必须创建第二个全局变量或将原始变量转换为数组并手动管理该数组(即,自行决定何时从内存中删除对象)

如果它已经由闭包创建,那么创建第二个、第三个和第四个实例可以通过反复调用创建闭包的函数来完成。您还可以获得额外的好处,即所有创建的实例在不再需要时自动进行垃圾收集

这种情况发生的频率比你想象的要高。假设您刚刚创建了一个动画序列,例如为文本设置动画以淡入。您使用了一个全局变量来跟踪动画的某些状态。你觉得这很好,一切都很好,忘了它吧。过了一段时间,你的老板来找你,说他喜欢这个动画,并想把它添加到页面的其他内容中。现在,您必须同时处理多个动画,并且需要将全局动画转换为数组,以防止一个动画撞击另一个正在进行的动画。。如果它们一开始就封装在闭包中就好了


你知道吗,当我提交这个答案后向下滚动时,我发现了一个问题,说明了全局变量的问题:。虽然对于这个特定的问题,你并不需要一个闭包,只需要简单的局部变量。

两个词:竞争条件

如果在全局范围内设置变量,而其预期用途是函数实例的本地用途,则可能会有两个(或更多)唯一实例访问和操作此全局变量,并且所有实例的行为都不可预测

在全局空间中存储局部状态时要格外小心,还有很多其他原因

一种方法是重新使用设置此变量的最后一个实例的状态(如果您没有同时激活多个实例)

还可能与依赖同名全局变量的其他代码片段发生冲突

从美学上讲,您还将全局名称空间变成了一团乱麻(那里有很多随机变量,没有任何直接的信息来说明它们为什么会在那里)

将变量放入全局空间容易出错,并且会将运行时视图弄得一团糟。JS的作用域可能性也使得它变得不必要,这就是为什么没有人这么做(除了真正属于那里的东西)


另外,在以后的问题中,不要提及你的年龄或吹嘘你的编码能力。这与问题无关。

离家时,最好将钥匙藏在天井周围一个大家都知道的地方,以便你的配偶可以收集钥匙,以防他/她早早回家,但把钥匙扔在路上不是个好主意。

“不想吹牛”,但你仍然这样做@盗贼大师:他很擅长吹牛,吹牛不费吹灰之力。如果你愿意被等着你把事情搞砸的人仔细观察,吹牛没什么错。@Josh:传统上,吹牛的人往往不知道自己在说什么(并作为副作用迅速上升到“管理”的水平)。Javascript忍者不会吹嘘,他们在沉默中进进出出,留下了可怕的代码。我不明白第一段与你的问题有什么关系。如果你不加上“我是个孩子,但我特别聪明”的字条,你害怕人们会否决你的问题吗?