【问题标题】:Why are closures better than global variables for preserving variables?为什么闭包比全局变量更好地保留变量?
【发布时间】:2010-12-27 00:19:32
【问题描述】:

我了解闭包在 JavaScript 中的工作原理,但我的问题是,您为什么要费尽心思制作闭包来保留变量?你不能把变量设为全局吗?或者这会使全局范围变得混乱并使您的代码容易出错。

【问题讨论】:

  • “不想吹牛”但你还是这样做了!
  • @ThiefMaster:他很擅长吹牛,它来得很轻松。
  • 如果你愿意被等着你搞砸的人审查,吹牛也没什么错。
  • @Josh:传统上,那些吹牛的人往往不知道他们在说什么(并迅速上升到“管理”级别作为副作用)。 Javascript Ninjas 不会吹牛,他们进进出出会默默地留下很棒的代码。
  • 我不明白第一段与您的问题有何关联。如果您不添加 i'm-a-kid-but-i'm-extra-smart 注释,您是否担心人们会否决您的问题?

标签: javascript closures


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    两个词:竞争条件

    如果您在全局范围内设置一个变量,而它的预期用途是一个 function 实例的本地变量,您将面临两个(或更多)唯一实例访问和操作此全局变量并具有所有实例的行为都无法预测。

    还有很多其他原因可以说明您在将本地状态存储在全局空间中时要格外小心。

    可能会重新使用设置此变量的最后一个实例的状态(如果您没有同时激活多个实例)。

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

    从美学上讲,您还会将全局命名空间变成一团糟(那里有很多随机变量,而没有任何直接信息来说明它们最初为何存在)。

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

    作为附加评论,不要在以后的问题中提及您的年龄或吹嘘您的编码能力。这与问题无关。

    【讨论】:

      【解决方案3】:

      好吧,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 的 implementation 类。 (免责声明,代码是我写的。)

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

      【讨论】:

        【解决方案4】:

        离开家时,最好将钥匙藏在露台周围的一个相互熟悉的地方,以便您的配偶可以收集它,以防他/她早点回家,但最好不要把它扔在路上.

        【讨论】:

          【解决方案5】:

          其中一个原因是防止全球污染。另一种是通过更改传递的值,对许多操作使用相同的实现。

          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
          

          【讨论】:

            【解决方案6】:

            其他人都已经提到了全球名称污染和global is evil,甚至是OP:

            或者这会使全局范围变得混乱......

            但还有另一个原因。

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

            如果它已经由闭包创建,则可以通过一次又一次地调用创建闭包的函数来简单地创建第二个、第三个和第四个实例。您还可以获得额外的好处,即所有创建的实例在不再需要时都会自动进行垃圾收集。

            这种情况发生的频率比你想象的要多。想象一下,您刚刚创建了一个动画序列,例如动画文本以淡入。您已经使用了一个全局变量来跟踪动画的某些状态。你认为这很好,一切都很好,然后忘记它。过了一段时间,你的老板来找你,说他喜欢这个动画,想把它添加到页面的其他内容中。现在您必须同时处理多个动画,并且需要将该全局转换为一个数组,以防止一个动画破坏另一个正在进行的动画..只要它们被封装在闭包中......


            您知道吗,就在我提交此答案后向下滚动时,我发现了一个说明全局变量问题的问题:How do you create multiple timers on one page that operate independently -- javascript?。虽然对于那个特定的问题,你并不需要一个闭包,只需要普通的局部变量。

            【讨论】:

              猜你喜欢
              • 2015-11-24
              • 1970-01-01
              • 2014-01-25
              • 1970-01-01
              • 1970-01-01
              • 2017-12-30
              • 2012-02-26
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多