我问了一个关于curry和闭包的问题。 什么是闭包?它和咖喱有什么关系?
当前回答
如果您来自Java世界,您可以将闭包与类的成员函数进行比较。看看这个例子
var f=function(){
var a=7;
var g=function(){
return a;
}
return g;
}
函数g是一个闭包:g封闭a。g可以和成员函数比较,a可以和类域比较,函数f可以和类比较。
其他回答
下面的示例演示了Scheme编程语言中的闭包。
首先定义一个函数,该函数定义了一个局部变量,在函数外部不可见。
; Function using a local variable
(define (function)
(define a 1)
(display a) ; prints 1, when calling (function)
)
(function) ; prints 1
(display a) ; fails: a undefined
下面是同样的例子,但是现在函数使用了一个全局变量,定义在函数外部。
; Function using a global variable
(define b 2)
(define (function)
(display b) ; prints 2, when calling (function)
)
(function) ; prints 2
(display 2) ; prints 2
最后,这里有一个函数携带自己闭包的例子:
; Function with closure
(define (outer)
(define c 3)
(define (inner)
(display c))
inner ; outer function returns the inner function as result
)
(define function (outer))
(function) ; prints 3
博士tl;
闭包是一个函数,它的作用域赋给(或用作)一个变量。因此,名称闭包:作用域和函数被封闭起来,并像其他实体一样使用。
维基百科式的深度解释
根据维基百科,闭包是:
在具有一流函数的语言中实现词法作用域名称绑定的技术。
这是什么意思?让我们来看看一些定义。
我将通过下面的例子解释闭包和其他相关定义:
函数startAt(x) { 返回函数(y) { 返回x + y; } } var closure1 = startAt(1); var closure2 = startAt(5); console.log (closure1 (3));// 4 (x == 1, y == 3) console.log (closure2 (3));// 8 (x == 5, y == 3)
一级函数
基本上,这意味着我们可以像使用其他实体一样使用函数。我们可以修改它们,将它们作为参数传递,从函数中返回它们,或者将它们分配给变量。从技术上讲,它们是一等公民,因此得名:一等功能。
在上面的例子中,startAt返回一个(匿名)函数,该函数被分配给closure1和closure2。如你所见,JavaScript对待函数就像对待其他实体一样(一级公民)。
名绑定
名称绑定是关于找出变量(标识符)引用的数据。作用域在这里非常重要,因为它将决定如何解析绑定。
在上面的例子中:
在内部匿名函数的作用域中,y被绑定为3。 在startAt的作用域中,x被绑定为1或5(取决于闭包)。
在匿名函数的作用域中,x没有绑定到任何值,因此需要在upper (startAt)作用域中解析它。
词法作用域
正如维基百科所说,范围:
是计算机程序中绑定有效的区域:其中的名称可用于引用实体。
有两种方法:
词法(静态)作用域:通过搜索包含变量的块或函数来解析变量的定义,如果搜索外部包含块失败,依此类推。 动态作用域:先搜索调用函数,然后搜索调用该函数的函数,依此类推,在调用堆栈中向上移动。
更多的解释,看看这个问题,看看维基百科。
在上面的例子中,我们可以看到JavaScript是词法范围的,因为当解析x时,绑定是在上层(startAt的)范围内搜索的,基于源代码(寻找x的匿名函数是在startAt内部定义的),而不是基于调用堆栈,函数被调用的方式(范围)。
裹(合)起来
In our example, when we call startAt, it will return a (first-class) function that will be assigned to closure1 and closure2 thus a closure is created, because the passed variables 1 and 5 will be saved within startAt's scope, that will be enclosed with the returned anonymous function. When we call this anonymous function via closure1 and closure2 with the same argument (3), the value of y will be found immediately (as that is the parameter of that function), but x is not bound in the scope of the anonymous function, so the resolution continues in the (lexically) upper function scope (that was saved in the closure) where x is found to be bound to either 1 or 5. Now we know everything for the summation so the result can be returned, then printed.
现在您应该了解闭包及其行为,这是JavaScript的基本部分。
局部套用
哦,您还了解了curry的含义:您使用函数(闭包)来传递操作的每个参数,而不是使用带有多个参数的一个函数。
闭包为JavaScript提供状态。
状态在编程中仅仅意味着记忆。
例子
var a = 0;
a = a + 1; // => 1
a = a + 1; // => 2
a = a + 1; // => 3
在上面的例子中,state存储在变量“a”中。我们在a后面加几次1。我们之所以能够这样做,是因为我们能够“记住”这个值。状态符“a”将该值保存在内存中。
通常,在编程语言中,您希望跟踪事物、记住信息并在以后访问它。
在其他语言中,这通常是通过使用类来实现的。类,就像变量一样,跟踪它的状态。而该类的实例,依次在它们内部也有状态。状态仅仅意味着您以后可以存储和检索的信息。
例子
class Bread {
constructor (weight) {
this.weight = weight;
}
render () {
return `My weight is ${this.weight}!`;
}
}
我们如何从“渲染”方法中访问“权重”?好吧,感谢国家。Bread类的每个实例都可以通过从“状态”(内存中存储信息的地方)读取它来呈现自己的权重。
JavaScript是一种非常独特的语言,它在历史上没有类(现在有了,但在底层只有函数和变量),所以闭包为JavaScript提供了一种记忆事物并在以后访问它们的方法。
例子
var n = 0;
var count = function () {
n = n + 1;
return n;
};
count(); // # 1
count(); // # 2
count(); // # 3
上面的例子实现了用变量“保持状态”的目标。这太棒了!然而,这有一个缺点,即变量(“状态”holder)现在是公开的。我们可以做得更好。我们可以使用闭包。
例子
var countGenerator = function () {
var n = 0;
var count = function () {
n = n + 1;
return n;
};
return count;
};
var count = countGenerator();
count(); // # 1
count(); // # 2
count(); // # 3
这太棒了。
现在我们的count函数可以计数了。它之所以能够这样做,是因为它可以“保持”状态。这种情况下的状态是变量“n”。这个变量现在关闭了。在时间和空间上封闭。因为你永远无法恢复它,改变它,给它赋值或直接与它交互。在空间中,因为它在地理上嵌套在“countGenerator”函数中。
为什么这很神奇?因为不需要涉及任何其他复杂的工具(例如类、方法、实例等),我们就能够 1. 隐藏 2. 从远处控制
我们隐藏了状态,变量“n”,这使它成为一个私有变量! 我们还创建了一个API,可以以预定义的方式控制这个变量。特别地,我们可以像这样调用API“count()”,它从“距离”将1加到“n”。除非通过API,否则任何人都无法访问“n”。
JavaScript的简单性确实令人惊叹。
闭包是其中一个重要原因。
闭包 只要在另一个函数内部定义了一个函数,内部函数就可以访问声明的变量 在外层函数中。闭包最好用例子来解释。 在清单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
封闭非常简单。我们可以这样考虑: 闭包=函数+它的词汇环境
考虑以下函数:
function init() {
var name = “Mozilla”;
}
在上述情况下,闭包是什么? 函数init()及其词法环境中的变量,即name。 闭包= init() + name
考虑另一个函数:
function init() {
var name = “Mozilla”;
function displayName(){
alert(name);
}
displayName();
}
这里的闭包是什么? 内部函数可以访问外部函数的变量。displayName()可以访问父函数init()中声明的变量名。但是,如果displayName()中存在相同的局部变量,则将使用它们。
闭包1:init函数+ (name变量+ displayName()函数)——>词法作用域
闭包2:displayName函数+(名称变量)——>词法范围