简体   繁体   English

为什么闭包比全局变量更适合保存变量?

[英]Why are closures better than global variables for preserving variables?

I understand how closures work within JavaScript, but my question is why would you go through all the trouble of making a closure to preserve a variable?我理解闭包在 JavaScript 中是如何工作的,但我的问题是为什么你要费尽心思地创建一个闭包来保存一个变量? Couldn't you just make the variable global?你不能把变量设为全局变量吗? Or would that clutter up the global scope and make your code be prone to errors.或者这会扰乱全局范围并使您的代码容易出错。

It's a scoping issue.这是一个范围界定问题。 Global variables are just that: Global, to everyone .全局变量就是:全局,对每个人 With closures, the scope (visibility) of the variables can be better controlled, which means the possible unintended side effects can be better controlled.使用闭包,可以更好地控制变量的范围(可见性),这意味着可以更好地控制可能的意外副作用。

http://en.wikipedia.org/wiki/Global_variable http://en.wikipedia.org/wiki/Global_variable

[Globals] are usually considered bad practice precisely because of their non-locality: a global variable can potentially be modified from anywhere (unless they reside in protected memory), and any part of the program may depend on it. [Globals] 通常被认为是不好的做法,正是因为它们的非局部性:全局变量可能从任何地方被修改(除非它们驻留在受保护的内存中),并且程序的任何部分都可能依赖于它。 A global variable therefore has an unlimited potential for creating mutual dependencies, and adding mutual dependencies increases complexity.因此,全局变量具有创建相互依赖关系的无限潜力,并且添加相互依赖关系会增加复杂性。 See action at a distance 远距离观看动作

Two words: race conditions .两个词:竞争条件

If you set a variable in the global scope while its intended usage is local to a function instance you run the risk of having two (or more) unique instances accessing and manipulating this global variable and having all instances behave unpredictably.如果您在全局范围内设置一个变量,而它的预期用途是函数实例的本地变量,您将面临让两个(或更多)唯一实例访问和操作该全局变量并使所有实例行为不可预测的风险。

There are plenty of other reasons why you should be extremely careful about storing local state in the global space.在全局空间中存储本地状态时,您应该格外小心的原因还有很多。

One would be re-using the state of the last instance that set this variable (if you don't have multiple instances active simultaneously).一种是重新使用设置此变量的最后一个实例的状态(如果您没有同时激活多个实例)。

There are also possible conflicts with other pieces of code that rely on a global variable with the same name.还可能与依赖同名全局变量的其他代码片段发生冲突。

Aesthetically you also turn the global namespace into a mess (lots of random variables there without any direct information as to why they are there in the first place).从美学上讲,您还会将全局名称空间变成一团糟(那里有很多随机变量,但没有任何直接信息说明它们为什么首先存在)。

Putting variables into the global space is error-prone and makes a mess of the runtime view.将变量放入全局空间很容易出错,并且会弄乱运行时视图。 The scoping possibilities of JS also make it unnecessary, which is why nobody does it (except for things that really belong there). JS 的作用域可能性也使它变得不必要,这就是为什么没有人这样做的原因(除了真正属于那里的东西)。

As an additional comment, don't mention your age or brag about your coding prowess in future questions.作为附加评论,不要在以后的问题中提及您的年龄或吹嘘您的编码能力。 It's not relevant to the question.这与问题无关。

While leaving home it is good idea to hide the key around the patio in a mutually known place so that your spouse can collect it in case if he/she comes home early but it is NOT good idea to throw it on the road.离开家时,最好将钥匙藏在院子周围一个大家都知道的地方,这样您的配偶可以在他/她提早回家的情况下领取它,但最好不要把它扔在路上。

Well there is only one global namespace in JavaScript, so it would be pretty hard to use different Frameworks/Toolkits on the same page, because sooner or later, variable names would begin to clash.好吧,在 JavaScript 中只有一个全局命名空间,因此在同一页面上使用不同的框架/工具包将非常困难,因为迟早变量名称会开始冲突。

Also closures provide a way to emulate private variables:闭包还提供了一种模拟私有变量的方法:

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

       get: function() {
           return count; // only gives you the value, but no write access
       }
   }
}

But that's a rather "dumb" example, closures are especially helpful when it comes to callbacks of all sorts, you don't want to manage global arrays which hold the data for each callback, it a lot simple, and cleaner with closures.但这是一个相当“愚蠢”的例子,闭包在涉及各种回调时特别有用,您不想管理为每个回调保存数据的全局数组,它非常简单,并且闭包更清晰。

For an extreme use of closures take a look at a Class implementation for JavaScript.对于闭包的极端使用,请查看 JavaScript 的类实现 (Disclaimer, code was written by me.) (免责声明,代码是我写的。)

Here proto keeps track of the raw properties of each class, but it's still available to extend which then can add those properties to other classes when they inherit from another.这里proto跟踪每个类的原始属性,但它仍然可以extend ,然后可以在其他类继承时将这些属性添加到其他类。

One of the reasons is to prevent global pollution.原因之一是为了防止全球污染。 The other is to use the same implementation for many operations just by changing the value passed.另一种是仅通过更改传递的值对许多操作使用相同的实现。

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

Everyone else have already mentioned golbal name pollution and global is evil , even the OP:其他人都已经提到了 golbal name pollution 和global is evil ,甚至是 OP:

Or would that clutter up the global scope...或者这会使全球范围变得混乱......

but there is one other reason.但还有另外一个原因。

There is only one instance of a global variable.全局变量只有一个实例。 This makes it not scale well.这使得它不能很好地扩展。 If at some point in the future you need more than one instance of the object you will either have to create a second global variable or convert the original variable into an array and manage that array manually (ie. decide for yourself when to delete the object from memory).如果在将来的某个时候您需要对象的多个实例,您将必须创建第二个全局变量或将原始变量转换为数组并手动管理该数组(即自行决定何时删除对象从记忆里)。

If it is already created by a closure then creating the second, third and fourth instances can be simply done by calling the function that creates the closure again and again.如果它已经由闭包创建,那么创建第二个、第三个和第四个实例可以简单地通过一次又一次地调用创建闭包的函数来完成。 You also get the added bonus that all created instances get automatically garbage collected when no longer needed.您还可以获得额外的好处,即所有创建的实例在不再需要时会自动进行垃圾回收。

This situation happens more often than you think.这种情况比你想象的更频繁地发生。 Imagine you've just created an animation sequence, animating a text to fade in for example.想象一下,您刚刚创建了一个动画序列,例如动画文本淡入。 And you've used a global variable to keep track of some state of the animation.并且您使用了一个全局变量来跟踪动画的某些状态。 And you think that's great and all's good and forget about it.你认为那很好,一切都很好,然后忘记它。 Then some time later your boss comes to you and says he likes the animation and would like to add it to other things in the page.然后过了一段时间,你的老板来找你,说他喜欢这个动画,想把它添加到页面的其他地方。 Now you have to deal with handling multiple animations at once and need to convert that global to an array to prevent one animation from clobbering another ongoing animation.. if only they were encapsulated in closures to begin with...现在你必须处理一次处理多个动画,并且需要将该全局转换为一个数组以防止一个动画破坏另一个正在进行的动画..如果只是它们被封装在闭包中开始......


And what do you know, just as I was scrolling down after I submitted this answer I found a question illustrating the problem with global variables: How do you create multiple timers on one page that operate independently -- javascript?你知道吗,就在我提交此答案后向下滚动时,我发现了一个说明全局变量问题的问题: How do you create multiple timers on one page that operational independently -- javascript? . . Though for that specific problem you don't really need a closure, just plain-old local variables.尽管对于那个特定问题,您实际上并不需要闭包,只需要普通的局部变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM