我问了一个关于curry和闭包的问题。 什么是闭包?它和咖喱有什么关系?


当前回答

下面是另一个现实生活中的例子,使用了游戏中流行的脚本语言——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”与函数一起存储的副本。

其他回答

从Lua.org:

当一个函数被封装在另一个函数中编写时,它可以完全访问封装函数中的局部变量;这个特性称为词法作用域。尽管这听起来很明显,但事实并非如此。词法作用域加上第一类函数是编程语言中一个强大的概念,但很少有语言支持这个概念。

curry:它允许你通过只传入函数参数的子集来部分求值。考虑一下:

function multiply (x, y) {
  return x * y;
}

const double = multiply.bind(null, 2);

const eight = double(4);

eight == 8;

闭包:闭包只不过是访问函数作用域之外的变量。重要的是要记住,函数中的函数或嵌套函数不是闭包。当需要访问函数作用域外的变量时,总是使用闭包。

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}

apple(3);

// the answer here will be 21

如果您来自Java世界,您可以将闭包与类的成员函数进行比较。看看这个例子

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

函数g是一个闭包:g封闭a。g可以和成员函数比较,a可以和类域比较,函数f可以和类比较。

首先,与这里大多数人告诉你的相反,闭包不是一个函数!那么它是什么呢? 它是在函数的“周围上下文”(称为其环境)中定义的一组符号,使其成为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.

闭包 只要在另一个函数内部定义了一个函数,内部函数就可以访问声明的变量 在外层函数中。闭包最好用例子来解释。 在清单2-18中,可以看到内部函数可以访问变量variableInOuterFunction 外的范围。外部函数中的变量已被内部函数封闭(或绑定在)。因此才有了这个术语 关闭。这个概念本身很简单,也很直观。

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;

     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

来源:http://index-of.es/Varios/Basarat%20Ali%20Syed%20 (auth)。他们% 20 node.js-apress % 20 (2014) . pdf