难以理解闭包的例子

时间:2015-02-05 14:27:30

标签: closures

在我尝试理解闭包是什么时,我在理解Closure维基百科文章中提供的以下示例时遇到了问题。 WikiPage。 能否帮助我理解这一点,并在这样做时提供一个易于理解的闭包定义。

function startAt(x)
   function incrementBy(y)
       return x + y
   return incrementBy

variable closure1 = startAt(1)
variable closure2 = startAt(5)

1 个答案:

答案 0 :(得分:0)

要了解闭包,首先需要了解范围。范围是变量的生命周期。在范围内声明的变量已经生成,并且在范围结束时它将死亡。例如:

{              // scope begins
    var x = 0; // variable x is born
    var y = 1; // variable y is born
}              // scope ends, x and y both die

现在,即使在声明结束的范围之后,也有一种方法可以使变量保持活动状态。简而言之,这是变量可以欺骗死亡的一种方式。变量欺骗死亡的方式是通过封闭。

考虑另一个范围内的范围。内部作用域可以访问外部作用域内声明的所有变量。但是,外部作用域不能访问在内部作用域内声明的任何变量。

{                  // the outer scope has access to x and y only
    var x = 0;
    var y = 1;

    {              // the inner scope has access to x, y and z
        var z = 2;
    }
}

内部作用域可以访问z,因为它在内部作用域中声明。但是,它也可以访问xy,因为这两个变量位于内部范围的词法环境(即父范围)中。

现在考虑如果我们可以将这个内部范围移到外部范围之外会发生什么。

{                  // the outer scope has access to x and y only
    var x = 0;
    var y = 1;

    {              // the inner scope has access to x, y and z
        var z = 2;
    } ---+
}        |
         |
{ <------+         // the inner scope moved outside of the outer scope
    var z = 2;
}

在这种情况下,外部范围结束。因此,xy应该与外部范围一起死亡。然而,它们不能死亡,因为内部范围仍然需要它们。当内部范围移动到外部范围之外时,它变为变量xy(它们的upvalues)的闭包,并且只要它自身存在,它就会使这些变量保持活动状态。这就是关闭的一般想法。

现在考虑以下代码:

function startAt(x) {
    return incrementBy;

    function incrementBy(y) {
        return x + y;
    }
}

var closure1 = startAt(1);
var closure2 = startAt(5);

这里,incrementBy函数是一个内部函数。因此,它可以访问属于x函数的变量startAt。但是,当我们从incrementBy返回startAt时,我们将内部函数移到外部函数之外。因此,尽管x应该在startAt返回时死亡,但它会继续生效,因为incrementBy需要它。

因此,incrementBy是一个闭包,因为它关闭变量x并使其保持活着,只要它自身存在;变量x称为闭包incrementBy的upvalue。