嵌套函数,闭包和范围

时间:2016-04-30 02:03:56

标签: javascript nested closures lexical-scope lexical-closures

我一直试图将我的头围绕着范围,特别是封闭。 我知道有很多关于这个主题的帖子,我一直在读很多。但大多数地方都将该主题称为高级主题,并使用相对难以掌握的术语。我想绝对肯定我已经掌握了正确的基础知识,所以我不会冒险进入更复杂的主题,错误地了解函数是如何工作的。

所以...我选择了一个基本的功能,并且真的希望有人告诉我,我认为它发生在引擎盖的内容是实际发生的事情。

这是代码:

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)。这是对的吗?

我已经制作了一个步骤图。

Diagram

3 个答案:

答案 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(一个函数式编程术语)。您在此示例中混合了curryingclosure这两个概念。

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是未分配的变量,其值为1b变量的值为function(b) {return a+b}。当我们连接这两个时,最终输出为1function(b) {return a+b}

N.B。 - a)如果您想要一个+ b的总和而不是那个奇怪的输出,只需将最后一行更改为console.log(sum(1)(2))。 b)如果你注意到函数#2中的值为{2的闭包a,那么除了活着之外,它永远不会被使用。