我问了一个关于curry和闭包的问题。 什么是闭包?它和咖喱有什么关系?
当前回答
下面的示例演示了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
其他回答
请看看下面的代码,以更深入地理解闭包:
for(var i=0; i< 5; i++){
setTimeout(function(){
console.log(i);
}, 1000);
}
这里会输出什么?0 1 2 3 4不是5 5 5 5 5 5 5 5 5因为是闭包的
那么它将如何解决呢?答案如下:
for(var i=0; i< 5; i++){
(function(j){ //using IIFE
setTimeout(function(){
console.log(j);
},1000);
})(i);
}
让我简单解释一下,当一个函数创建时,直到它在第一个代码中调用5次for循环才会发生,但不会立即调用所以当它在1秒后调用i.e时,这也是异步的,所以在这个for循环结束之前,将值5存储在var i中最后执行5次setTimeout函数并打印5,5,5,5,5
这里如何解决使用IIFE即立即调用函数表达式
(function(j){ //i is passed here
setTimeout(function(){
console.log(j);
},1000);
})(i); //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4
要了解更多,请了解执行上下文以理解闭包。
还有一个解决方案来解决这个问题,使用let (ES6特性),但在引子下面,上面的函数是工作的 (让我= 0;我< 5;我+ +){ setTimeout(函数(){ console.log(我); }, 1000); } 输出:0,1,2,3,4
更多解释:
在内存中,当for循环执行时,图片如下所示:
1)循环
setTimeout(function(){
console.log(i);
},1000);
2)循环
setTimeout(function(){
console.log(i);
},1000);
3)循环
setTimeout(function(){
console.log(i);
},1000);
4)循环
setTimeout(function(){
console.log(i);
},1000);
循环5)
setTimeout(function(){
console.log(i);
},1000);
这里没有执行i,然后在完成循环后,var i在内存中存储值5,但它的作用域在它的子函数中始终可见,因此当函数在setTimeout内执行五次时,它打印5,5,5,5,5
所以解决这个问题使用IIFE如上所述。
在正常情况下,变量受作用域规则约束:局部变量仅在定义的函数内工作。闭包是为了方便而暂时打破这一规则的一种方式。
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。
闭包是一个可以引用另一个函数中的状态的函数。例如,在Python中,它使用闭包"inner":
def outer (a):
b = "variable in outer()"
def inner (c):
print a, b, c
return inner
# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1
我将给出一个例子(JavaScript):
function makeCounter () {
var count = 0;
return function () {
count += 1;
return count;
}
}
var x = makeCounter();
x(); returns 1
x(); returns 2
...etc...
这个makeCounter函数的作用是,它返回一个函数,我们称之为x,每次调用它都会加1。由于我们没有为x提供任何参数,它必须以某种方式记住计数。它知道根据所谓的词法作用域在哪里找到它——它必须查找定义值的位置才能找到值。这个“隐藏”值就是所谓的闭包。
下面还是我用咖喱的例子:
function add (a) {
return function (b) {
return a + b;
}
}
var add3 = add(3);
add3(4); returns 7
您可以看到,当您使用参数a(即3)调用add时,该值包含在我们定义为add3的返回函数的闭包中。这样,当我们调用add3时,它知道在哪里找到a值来执行加法。
如果您来自Java世界,您可以将闭包与类的成员函数进行比较。看看这个例子
var f=function(){
var a=7;
var g=function(){
return a;
}
return g;
}
函数g是一个闭包:g封闭a。g可以和成员函数比较,a可以和类域比较,函数f可以和类比较。