为什么闭包比全局变量更能保存变量?
我了解闭包在 JavaScript 中的工作原理,但我的问题是为什么要费尽心思创建闭包来保存变量?不能把变量设为全局吗?或者这会扰乱全局范围并使您的代码容易出错。
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? Couldn't you just make the variable global? Or would that clutter up the global scope and make your code be prone to errors.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是一个范围界定问题。全局变量就是这样:全局的,对每个人来说。使用闭包,可以更好地控制变量的范围(可见性),这意味着可以更好地控制可能的意外副作用。
http://en.wikipedia.org/wiki/Global_variable
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
两个词:竞争条件。
如果您在全局范围内设置一个变量,而其预期用途是函数实例的本地变量,那么您将面临两个(或更多)唯一实例访问和操作此全局变量并使所有实例行为相同的风险不可预测。
还有很多其他原因导致您在全局空间中存储本地状态时应该非常小心。
一种方法是重新使用设置此变量的最后一个实例的状态(如果您没有同时活动多个实例)。
也可能与依赖同名全局变量的其他代码片段发生冲突。
从美学上讲,您还将全局名称空间变得一团糟(那里有很多随机变量,没有任何直接信息说明它们为什么在那里)。
将变量放入全局空间很容易出错,并且会使运行时视图变得混乱。 JS 的范围界定可能性也使其变得不必要,这就是为什么没有人这样做(除了真正属于那里的东西)。
作为附加评论,请勿在以后的问题中提及您的年龄或吹嘘您的编码能力。这与问题无关。
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).
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.
JavaScript 中只有一个全局命名空间,因此在同一页面上使用不同的框架/工具包将非常困难,因为变量名称迟早会开始冲突。
闭包还提供了一种模拟私有变量的方法:
但这是一个相当“愚蠢”的例子,闭包在涉及各种回调时特别有用,你不想管理保存每个回调数据的全局数组,它非常简单,并且带有闭包更干净。
对于闭包的极端使用,请查看类实现对于 JavaScript。 (免责声明,代码是我编写的。)
这里
proto
跟踪每个类的原始属性,但它仍然可以用于extend
,然后可以将这些属性添加到其他类当类从另一个类继承时。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.
Also closures provide a way to emulate private variables:
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. (Disclaimer, code was written by me.)
Here
proto
keeps track of the raw properties of each class, but it's still available toextend
which then can add those properties to other classes when they inherit from another.离开家时,最好将钥匙藏在庭院周围一个大家都知道的地方,以便您的配偶可以在他/她提早回家时领取钥匙,但最好不要把钥匙扔在路上。
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.
原因之一是防止全球污染。另一种是通过更改传递的值来对许多操作使用相同的实现。
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.
其他人都已经提到了全球名称污染和全球是邪恶的,甚至OP:
但还有另一个原因。
全局变量只有一个实例。这使得它不能很好地扩展。如果在将来的某个时刻您需要该对象的多个实例,您将必须创建第二个全局变量或将原始变量转换为数组并手动管理该数组(即自己决定何时删除该对象)从记忆中)。
如果它已经由闭包创建,则可以通过一次又一次调用创建闭包的函数来简单地创建第二个、第三个和第四个实例。您还可以获得额外的好处,即所有创建的实例在不再需要时都会自动进行垃圾收集。
这种情况发生的频率比您想象的要高。假设您刚刚创建了一个动画序列,例如将文本设置为淡入动画。并且您使用了全局变量来跟踪动画的某些状态。你认为这很好,一切都很好,然后就忘记它了。一段时间后,您的老板来找您并说他喜欢该动画并希望将其添加到页面中的其他内容中。现在,您必须同时处理多个动画,并且需要将全局转换为数组,以防止一个动画破坏另一个正在进行的动画。如果它们一开始就封装在闭包中...
您知道什么,正如我在提交此答案后向下滚动时,我发现了一个说明全局变量问题的问题: How do you create multiple timers on one page that独立运行——javascript?。尽管对于该特定问题,您实际上并不需要闭包,只需要普通的局部变量。
Everyone else have already mentioned golbal name pollution and global is evil, even the OP:
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?. Though for that specific problem you don't really need a closure, just plain-old local variables.