我问了一个关于柯里化的问题,提到了闭包。什么是闭包?它与柯里化有什么关系?
我问了一个关于柯里化的问题,提到了闭包。什么是闭包?它与柯里化有什么关系?
def n_times(a_thing)
return lambda{|n| a_thing * n}
end
lambda(|n| a_thing * n}
是闭包,因为lambda(一个匿名函数创建者)引用了a_thing
。foo = n_times(4)
foo将打破正常的作用域规则并开始在内部使用4。
foo.call(3)
返回 12。
在编程中,状态简单地指记住事情。
示例
var a = 0;
a = a + 1; // => 1
a = a + 1; // => 2
a = a + 1; // => 3
class Bread {
constructor (weight) {
this.weight = weight;
}
render () {
return `My weight is ${this.weight}!`;
}
}
var n = 0;
var count = function () {
n = n + 1;
return n;
};
count(); // # 1
count(); // # 2
count(); // # 3
上面的示例通过变量实现了“保持状态”的目标。这很好!然而,这种方法的缺点是变量(即“状态”持有者)现在被暴露出来了。我们可以做得更好。我们可以使用闭包。
示例
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”。任何人都无法通过任何方式访问“n”,除非通过API。
这部分原因在于闭包。
var f=function(){
var a=7;
var g=function(){
return a;
}
return g;
}
g
是一个闭包:它在a
中关闭。因此,g
可以与成员函数进行比较,a
可以与类字段进行比较,而函数f
则可以与类进行比较。; 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
柯里化:它允许您仅通过传递其子集来部分评估函数。考虑以下内容:
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
local old_dofile = dofile
function dofile( filename )
if filename == nil then
error( 'Can not use default of stdin.' )
end
old_dofile( filename )
end
来自Lua.org:
当一个函数被写在另一个函数中时,它可以完全访问封闭函数的本地变量;这个特性被称为词法作用域。虽然这听起来很明显,但实际上并不是。词法作用域加上一级函数是编程语言中的一个强大概念,但很少有语言支持这个概念。
for(var i=0; i< 5; i++){
setTimeout(function(){
console.log(i);
}, 1000);
}
以下是代码输出结果:
0, 1, 2, 3, 4
不会是 5,5,5,5,5
,因为闭包的原因。
那么如何解决呢?答案如下:
for(var i=0; i< 5; i++){
(function(j){ //using IIFE
setTimeout(function(){
console.log(j);
},1000);
})(i);
}
让我简单解释一下,当一个函数被创建时,除非被调用否则不会发生任何事情。所以第一个代码中的for循环调用了5次,但并没有立即调用, 因此在1秒之后才会调用。由于是异步的,因此在这个for循环完成并将值5存储在变量i中之前,最终执行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特性)解决这个问题的解决方案,但在上面的函数底层工作。 for(let i=0; i< 5; i++){
setTimeout(function(){
console.log(i);
},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 没有被执行,然后在循环完成后,变量 i 存储了值 5 在内存中,但它的作用域始终可见于其子函数,因此当函数在 setTimeout
中执行五次时,它会打印出 5,5,5,5,5
因此,为了解决这个问题,请按照上面所述使用 IIFE。
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.)-Beginning%20Node.js-Apress%20(2014).pdf