我一直试图将我的头围绕着范围,特别是封闭。 我知道有很多关于这个主题的帖子,我一直在读很多。但大多数地方都将该主题称为高级主题,并使用相对难以掌握的术语。我想绝对肯定我已经掌握了正确的基础知识,所以我不会冒险进入更复杂的主题,错误地了解函数是如何工作的。
所以...我选择了一个基本的功能,并且真的希望有人告诉我,我认为它发生在引擎盖的内容是实际发生的事情。
这是代码:
function sum(a) {
return function(b) {
return a+b
}
}
console.log( sum(1)(sum(2)))
(我知道它实际上并没有做到这一点,我用它进行了调整,试图了解每一步中发生了什么。)
所以,我的主要怀疑是为什么A是1,而不是2.我得出结论,只要创建function(b)
以将sum(2)
作为参数,就会创建闭包,由sum(1)
返回后。因此,通过闭包的定义,我假设在创建函数时它还保存了词法环境(a = 1
)。这是对的吗?
我已经制作了一个步骤图。
答案 0 :(得分:0)
调用sum
时会创建一个范围。在此范围内,有一个形式参数a
和一个内部的匿名函数,它会立即返回。这个匿名函数是一个闭包,因为它捕获了它的封闭函数(sum
)的范围。因此,此内部函数可以访问a
。
现在我们明显地混淆了你:内部函数只获得sum的范围的副本,而不是对原始范围的引用。这意味着如果我们从sum
返回并因此消除其范围,则此副本不受影响(内部函数的a
保持为1)。具有不同参数的sum
的进一步函数调用也不会影响闭包。
结论:闭包可以存在比其封闭函数更长的时间。
从技术上讲,a
sum
存储在堆栈中,而闭包的捕获a
存储在堆中,因此与{{1}的生命周期无关}。
顺便说一句,你在这里所做的就叫做currying。而不是用多个参数调用sum
,而是在程序上调用它,每个调用只有一个参数:
sum
答案 1 :(得分:-1)
无论我们使用什么设施来传输其词法范围之外的内部函数,它都会保持范围引用它最初声明的位置,并且无论我们在何处执行它,都将执行闭包。
在下一个函数中,您将看到greet
如何使用在salute
函数内声明的变量greeting
,即使不再调用它,也称为闭包。
function greeting(name) {
var salute = "Hello "; // This is a closure
return function() {
console.log(salute + name);
}
}
var greet = greeting("Dave");
greet(); // Hello Dave
您可以在Kyle Simpson的书籍系列You Don't Know JS中了解有关闭包的更多信息,但对于此特定主题,请检查You Don't Know JS: Scope & Closures。他使用一种简单易用的语言来解释像这样的困难概念。
答案 2 :(得分:-1)
这是发生的事情
1)如果一个函数返回一个函数,那么返回的函数会被立即调用,称为currying
(一个函数式编程术语)。您在此示例中混合了currying
和closure
这两个概念。
2)首先调用你的sum(1)
部分。将返回function(b) {return a+b}
(让我们将其称为#1st),但是它将使a
保持为1,仅用于#1st的上下文。
3)由于函数参数是函数调用本身,因此将调用该参数部分。例如sum(1)(sum(2))
,此处sum(2)
部分将被调用并返回function(b) {return a+b}
(让我们将其称为#2nd),同时它将保持a
为2的上下文#仅限第2次(关闭)。
4)现在我们立即用#2nd作为参数调用#1st作为参数的语法 - #1st(#2nd)
5)所以我们的a
是未分配的变量,其值为1
,b
变量的值为function(b) {return a+b}
。当我们连接这两个时,最终输出为1function(b) {return a+b}
N.B。 - a)如果您想要一个+ b的总和而不是那个奇怪的输出,只需将最后一行更改为console.log(sum(1)(2))
。 b)如果你注意到函数#2中的值为{2的闭包a
,那么除了活着之外,它永远不会被使用。