0

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

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

这是代码:

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

我已经制作了步骤图。

图表

4

3 回答 3

-1

这就是发生的事情

1)如果一个函数返回一个函数并且该返回的函数被立即调用,则被调用currying(一个函数式编程术语)。currying在此示例中,您混合closure了这两个概念。

2)首先你的sum(1)部分被调用。它将返回function(b) {return a+b}(让我们将其称为 #1st) ,但对于 #1st 的上下文,它将保持a为 1。

3)由于函数参数本身是一个函数调用,因此该参数部分将被调用。例如sum(1)(sum(2)),这里的sum(2)部分将被调用并返回function(b) {return a+b}(让我们将其称为#2nd),对于仅#2nd 的上下文(闭包),它将保持a为 2。

4) 现在我们立即调用 #1st 并使用 #2nd 作为参数,使用该柯里化语法 - #1st(#2nd)

5)所以我们a是未分配的变量并且有值1b变量有值function(b) {return a+b}。当我们连接这两者时,最终输出是1function(b) {return a+b}

注意 - a)如果你想要 a+b 的总和而不是那个奇怪的输出,只需将你的最后一行更改为console.log(sum(1)(2)). ab) 如果您注意到在被称为 #2nd 的函数中的值为 2 的闭包除了 alive 之外永远不会在任何地方使用。

于 2016-04-30T02:56:32.260 回答
-1

sum被调用时,它会创建一个范围。在这个范围内,有形式参数a和一个内部匿名函数,它会立即返回。这个匿名函数是一个闭包,因为它捕获了它的封闭函数 ( sum) 的范围。因此,这个内部函数可以访问a.

现在我们来到了明显让您感到困惑的一点:内部函数只获得 sum 范围的副本,而不是对原始范围的引用。这意味着如果我们从中返回sum并因此消除其范围,则此副本保持不变(a内部函数的保持为 1)。具有不同参数的进一步函数调用sum也不影响闭包。

结论:闭包可以比它的封闭函数存在的时间更长。

从技术上讲asum存储在堆栈中,而捕获a的闭包存储在堆中,因此与sum.

顺便说一句,你在这里做的事情叫做柯里化。您无需sum使用多个参数调用它,而是在程序上调用它,每次调用使用一个参数:

sum(1, 2); // multi argument form
sum(1)(2); // curry form
于 2016-05-10T16:09:16.043 回答
-1

无论我们使用什么工具将内部函数传输到其词法范围之外,它都会维护一个指向它最初声明位置的范围引用,并且无论我们在哪里执行它,都会执行该闭包。

在下一个函数中,您将看到即使不再调用它,它也将如何使用函数内部声明greet的变量,这称为闭包。salutegreeting

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。他使用一种简单而切题的语言来解释像这样的困难概念。

于 2016-04-30T02:20:23.750 回答