我问了一个关于curry和闭包的问题。 什么是闭包?它和咖喱有什么关系?
当前回答
简而言之,函数指针只是指向程序代码库中某个位置的指针(如程序计数器)。而Closure =函数指针+堆栈帧。
.
其他回答
首先,与这里大多数人告诉你的相反,闭包不是一个函数!那么它是什么呢? 它是在函数的“周围上下文”(称为其环境)中定义的一组符号,使其成为CLOSED表达式(即,每个符号都被定义并具有值的表达式,因此可以对其求值)。
例如,当你有一个JavaScript函数:
function closed(x) {
return x + 3;
}
它是一个封闭表达式,因为其中出现的所有符号都在其中定义(它们的含义是明确的),所以您可以对其求值。换句话说,它是独立的。
但如果你有一个这样的函数
function open(x) {
return x*y + 3;
}
它是一个开放的表达式,因为其中有尚未定义的符号。也就是y,当我们看这个函数的时候,我们不知道y是什么,它意味着什么,我们不知道它的值,所以我们不能计算这个表达式。也就是说,我们不能调用这个函数,直到我们知道y在其中的含义。这个y叫做自由变量。
这需要一个定义,但这个定义不是函数的一部分——它是在其他地方定义的,在它的“周围上下文”(也称为环境)中。至少这是我们所希望的:P
例如,它可以被全局定义:
var y = 7;
function open(x) {
return x*y + 3;
}
或者它可以定义在一个包装它的函数中:
var global = 2;
function wrapper(y) {
var w = "unused";
return function(x) {
return x*y + 3;
}
}
环境中赋予表达式中自由变量意义的部分是闭包。之所以这么叫,是因为它通过为所有自由变量提供这些缺失的定义,把一个开放表达式变成一个封闭表达式,这样我们就可以求值了。
在上面的例子中,内部函数(我们没有给出名称,因为我们不需要它)是一个开放表达式,因为其中的变量y是自由的——它的定义在函数之外,在包装它的函数中。这个匿名函数的环境是一组变量:
{
global: 2,
w: "unused",
y: [whatever has been passed to that wrapper function as its parameter `y`]
}
闭包是这个环境的一部分,它通过提供所有自由变量的定义来关闭内部函数。在我们的例子中,内部函数中唯一的自由变量是y,所以这个函数的闭包是它环境的这个子集:
{
y: [whatever has been passed to that wrapper function as its parameter `y`]
}
在环境中定义的另外两个符号不是该函数闭包的一部分,因为它不需要运行它们。他们不需要关闭它。
这里有更多的理论: https://stackoverflow.com/a/36878651/434562
It's worth to note that in the example above, the wrapper function returns its inner function as a value. The moment we call this function can be remote in time from the moment the function has been defined (or created). In particular, its wrapping function is no longer running, and its parameters which has been on the call stack are no longer there :P This makes a problem, because the inner function needs y to be there when it is called! In other words, it requires the variables from its closure to somehow outlive the wrapper function and be there when needed. Therefore, the inner function has to make a snapshot of these variables which make its closure and store them somewhere safe for later use. (Somewhere outside the call stack.)
And this is why people often confuse the term closure to be that special type of function which can do such snapshots of the external variables they use, or the data structure used to store these variables for later. But I hope you understand now that they are not the closure itself – they're just ways to implement closures in a programming language, or language mechanisms which allows the variables from the function's closure to be there when needed. There's a lot of misconceptions around closures which (unnecessarily) make this subject much more confusing and complicated than it actually is.
在正常情况下,变量受作用域规则约束:局部变量仅在定义的函数内工作。闭包是为了方便而暂时打破这一规则的一种方式。
def n_times(a_thing)
return lambda{|n| a_thing * n}
end
在上面的代码中,lambda(|n| a_thing * n}是闭包,因为a_thing是由lambda(匿名函数创建者)引用的。
现在,如果你把得到的匿名函数放到一个函数变量中。
foo = n_times(4)
Foo将打破正常的作用域规则,开始在内部使用4。
foo.call(3)
返回12。
闭包是JavaScript中的一个特性,函数可以访问自己的作用域变量、外部函数变量和全局变量。
闭包即使在外部函数返回之后也可以访问它的外部函数作用域。这意味着闭包可以记住并访问它的外部函数的变量和参数,即使函数已经完成。
内部函数可以访问在自己的作用域、外部函数的作用域和全局作用域中定义的变量。外部函数可以访问在自己的作用域和全局作用域中定义的变量。
闭包的例子:
var globalValue = 5;
function functOuter() {
var outerFunctionValue = 10;
//Inner function has access to the outer function value
//and the global variables
function functInner() {
var innerFunctionValue = 5;
alert(globalValue + outerFunctionValue + innerFunctionValue);
}
functInner();
}
functOuter();
输出将为20,即其内部函数自身变量、外部函数变量和全局变量值的和。
下面是另一个现实生活中的例子,使用了游戏中流行的脚本语言——Lua。我需要稍微改变一个库函数的工作方式,以避免stdin不可用的问题。
local old_dofile = dofile
function dofile( filename )
if filename == nil then
error( 'Can not use default of stdin.' )
end
old_dofile( filename )
end
当这段代码完成它的作用域时,old_dofile的值就消失了(因为它是本地的),但是该值已经被封装在一个闭包中,所以新的重新定义的dofile函数可以访问它,或者更确切地说,作为“upvalue”与函数一起存储的副本。
如果您来自Java世界,您可以将闭包与类的成员函数进行比较。看看这个例子
var f=function(){
var a=7;
var g=function(){
return a;
}
return g;
}
函数g是一个闭包:g封闭a。g可以和成员函数比较,a可以和类域比较,函数f可以和类比较。