闭包定义和示例

时间:2010-07-21 04:07:16

标签: closures

什么是封闭及其对应的例子?

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

请帮忙。

感谢。

3 个答案:

答案 0 :(得分:9)

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

function A() {
    var x = 5;

    function B() {
        print(x);
    }

    return B;
}

如果你来自C ++背景,这很难消化。当我们尝试调用A返回的函数时,它会引用什么xx终止后,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之前),那么clicked变量会在调用赋给$(document).ready()的函数时很久就会消失,并且单击回调的按钮会有未定义的行为。

答案 1 :(得分:1)

以下是我对闭包的看法......

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

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

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

以下是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)时,它会为调用创建一个堆栈条目,该条目包含保存值为5的变量x的版本。然后它声明函数closure范围。

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

答案 2 :(得分:0)