【问题标题】:Closure Definition and Example闭包定义和示例
【发布时间】:2011-03-18 19:07:58
【问题描述】:

什么是闭包及其对应示例?

我研究了很多,但无法理解。 请在通用编程语言概念方面和特定编程语言方面进行解释。

请帮忙。

谢谢。

【问题讨论】:

标签: closures


【解决方案1】:

闭包基本上是一个嵌套在函数A中的函数B,可以访问A的局部变量:

function A() {
    var x = 5;

    function B() {
        print(x);
    }

    return B;
}

如果你有 C++ 背景,这很难理解。当我们尝试调用 A 返回的函数时,x 会引用什么? x 不会因为 A() 终止而无效吗?

答案是x 确实存在。我们返回的B 实际上隐含地带有x。很酷吧?

在更一般的意义上,闭包是绑定到某些数据的函数。在像 C 这样没有闭包的语言中,每个程序都有固定数量的函数。从某种意义上说,使用闭包,您可以通过将它们绑定到动态数据来“创建函数”。当然,没有人会阻止你在 C 中模拟闭包,但有时会很痛苦。

闭包真的很有用。例如,假设我们要实现自己的“for循环”:

function loop(count, f) {
    for (var i = 0; i < count; i++)
        f(i);
}

var array = [0,1,2,3,4];

loop(5, function(i) {
    print(array[i]);
});

允许访问外部变量而无需做一堆额外的废话,使代码既美观又简单。如果没有闭包,您可能不得不将上下文变量传递给 loop 函数:

function loop(count, f, ctx) {
    for (var i = 0; i < count; i++)
        f(i, ctx);
}

var array = [0,1,2,3,4];

loop(5, function(i, ctx) {
    print(ctx[i]);
}, array);

另一个例子:假设我们想在 jQuery 中注册一个回调,但它可能在函数及其调用者及其调用者的调用者完成运行后很久才执行:

$(document).ready(function(){

    var clicked = 0;

    $('#button').click(function(){
        clicked++;
        alert("You've pressed the button " + clicked + " times.");
    });

});

如果 JavaScript 更像 C++(在 C++0x 之前),那么在调用 $(document).ready() 的函数时,clicked 变量将早已不复存在,并且按钮单击回调将具有未定义的行为。

【讨论】:

  • 有趣的是,C++0x 现在有 lambdas,可以从其封闭范围捕获变量。因此,“如果你来自 C++ 背景” 论点变得不那么相关了。
  • @Alexandre Jasmin - 这是一种非常奇怪的关闭形式。比大多数支持它们的语言更明确。虽然我实际上更喜欢这种方式。我认为您应该必须在封闭范围内说明您打算使用哪些变量。
  • @Omnifarious 实际上,C++ lambda 的 [&] 和 [=] 形式会自动捕获所有引用的变量。 C++ 中的 lambda 有点难以使用,因为变量生命周期比垃圾收集语言更棘手。因此,C++ 中的“您已按下按钮 x 次”示例的版本会不太优雅。我的观点是闭包和 lambda 现在变得越来越普遍。几年前我没想到会在 C++ 中看到它们。
【解决方案2】:

这是我对闭包的看法....

一个函数对象由两部分组成。第一件事是函数的代码,第二件事是它执行的范围。在闭包中,函数执行的范围和代码是相互分离的。相同的代码可以在多种范围内执行。

如果以完全不受限制的方式允许这样做,将会导致极大的混乱。即使它像动态范围一样松散(函数继承了调用它的地方的范围),它也会变得非常混乱。

闭包是一种指定范围规则的便捷方式,它非常有意义,因为它们只需要阅读代码而不是跟踪它。在闭包中,函数获取声明它的范围。如果它是在执行另一个函数时声明的,它将获得该函数堆栈的特定实例的范围。这比能够给出闭包和任意范围或动态范围要简单得多,也更容易理解。

以下是 Python 中一个普通闭包的示例:

def outer():
    def closure():
        pass
    return closure

这里的函数closure 是一个闭包。它实际上并没有使用定义它的范围内的任何变量,所以它非常简单,但它仍然是一个。

这是一个在 Python 中不那么简单但仍然很简单的闭包:

 def outer(x):
      def closure():
          return x
      return closure
 f1 = outer(5)
 f2 = outer(6)

调用f1() 将返回5,调用f2() 将返回6。如您所见,函数closure 是部分代码和部分范围。

outer(5) 被调用时,它会为调用创建一个堆栈条目,其中包含变量x 的一个版本,其值为5。然后它声明函数closure 获得该范围。

outer(6) 被调用时,它会为调用创建一个堆栈条目,其中包含变量x 的一个版本,其值为6。然后它声明函数closure 获得该范围。

【讨论】:

    【解决方案3】:

    如果你想要一个关于闭包的例子,我建议你去看看这本书

    深入了解 Python:第 6 章 - 闭包和生成器

    这本书是免费开放的,您可以在---> http://diveintopython3.org/

    下载它

    这个例子很有趣,清晰并且逐渐采用了更高级的方法。 我认为第一次曝光它很棒。

    看看吧,这里没有理由复制它,只要你可以简单地下载或在线阅读。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多