在 JavaScript 的上下文中说“将闭包分配给变量”是不是正确?

Posted

技术标签:

【中文标题】在 JavaScript 的上下文中说“将闭包分配给变量”是不是正确?【英文标题】:Is saying to "assign a closure to a variable" correct in the context of JavaScript?在 JavaScript 的上下文中说“将闭包分配给变量”是否正确? 【发布时间】:2021-02-02 08:47:03 【问题描述】:

我很好奇示例代码中第 20 行的解释。

在第 9 行声明了名为 func1 的变量。 已分配给 函数foo() 调用返回的闭包。`

我知道函数foo() 的调用会返回函数bar 和指向其词法范围内的变量a 的指针。既然闭包是a function combined with all of the variables in its lexical scope, including function and class names,我可以说我是把变量func1赋给闭包了吗?

这个解释是否使用了正确的词而不是含糊不清?你能提出一个更好更简洁的解释和解释第 20 行吗?

function foo() 
  let a = 1;
  return function bar() 
    a += 100;
    console.log(a);
  


let func1 = foo(); 
let func2 = foo();

func1(); // ???
func2(); // ???
func1(); // ???
func2(); // ???

/*
On line 9 variable with name `func1` is declared. 

!! It's assigned to the closure that is returned by the function `foo()` invocation. 

The closure contains a pointer to the variable `a` that is in the lexical scope of the function `bar` that is returned by the `foo` invocation.

On line 10 variable with name `func2` is declared. It's assigned to the value of closure that is returned by the function `bar()` invocation. The closure contains a pointer to the variable `a` that is in the lexical scope of the function `bar`.


Variables accessible through the closure during the `func1` invocation and `func2` invocation are two separate independent variables that just happen to have the same name (`a`). 

That is, this program would print the following to the console:
- 101
- 101
- 201
- 201
*/

【问题讨论】:

func1 在哪里?我个人说变量是“封闭的”,正如 Crockford 先生所说的那样。 我会避免说“分配了一个闭包”。这有点误导,太技术化了。 1. 赋值通常是设置变量的值,例如x = 1是将1赋值给x。你倒着说(意译)x 被分配给1。 2.“闭包”其实没什么特别的。 JS 中的每个函数都是一个闭包。我只想说foo() 是一个高阶函数,结果是一个函数。 【参考方案1】:

我知道函数 foo() 的调用会返回 函数 bar 和指向变量 a 的指针

闭包不是这样工作的。调用foo() 只返回函数bar,它不返回指向变量a 的指针。

每个环境都链接到它的外部环境,当javascript在当前环境中找不到变量时,它会跟随链接到外部环境。不同环境之间的这种联系使闭包成为可能。

当函数foo被定义时,javascript将指向全局环境的链接保存在一个槽中,该槽中规范调用函数的[[Environment]]槽。

当函数 foo 被调用时,会为该调用创建一个新环境,并将其链接到保存在函数 foo 上的 [[Environment]] 槽中的环境(让我们将此环境称为 EnvFoo .)

类似地,当定义bar 函数时,javascript 将在调用函数foo 时创建的环境链接(EnvFoo) 保存在[[Environment]] 插槽中bar 函数上。当调用bar 时,会创建一个新环境(让我们将此环境称为EnvBar),它会获得保存在bar 函数(EnvFoo)上[[Environment]] 槽中的环境的链接,作为其外部环境。

所以当你调用bar函数时,变量a在当前环境中不存在(EnvBar),所以javascript在当前环境的外部环境中寻找变量a,即@ 987654349@。这个环境包含变量a,所以它从这个外部环境中获取a的值,即EnvFoo

这就是闭包的工作原理,即每个环境都保持对其外部环境的引用,当 javascript 在当前环境中找不到变量时,它会跟随指向当前环境的外部环境的链接并在那里查找变量。它继续跟随外部环境的链接,直到它到达全球环境。

下图将让您了解每个环境在您的案例中是如何关联的。

P.S:我上面解释的都是我从@T.J Crowder'sbook学到的东西。如果你想了解更多细节,我建议你参考这本书,因为它在书中有详细的解释。

【讨论】:

:-) 感谢您的支持!【参考方案2】:

我知道函数 foo() 的调用会返回函数 bar 和指向其词法范围内的变量 a 的指针。

它只返回一件事:foo 创建的函数 bar。函数bar 本身具有对创建它的环境的引用,因此是对a 变量的引用;它关闭那个环境。所以bar 是一个闭包。您在 JavaScript 代码中创建的所有函数都是闭包。

...我可以说我将变量 func1 分配给闭包吗?

你不能给闭包分配任何东西;相反。您可以分配给变量(各种),您可以初始化常量。你在const func1 = foo(); 中所做的是用foo 返回的函数(如果你愿意,你可以说“闭包”)初始化常量func1

【讨论】:

TJ,所以,下面的解释会更好:在线[x]变量func1被初始化并分配给foo()调用返回的函数,其中包括指向变量@987654334的指针@. @DmytroNayda - 更接近,但没有“到”。变量func1 被分配了foo() 返回的函数。或者将foo() 返回的函数分配给 func1。 (然后,是的,该函数在概念上具有一个引用——我不会说“指针”——指向创建它的上下文,其中包含用于调用 fooa 变量。)跨度> @PeterSeliger - 谢谢,我写了foo,我的意思是bar! :-)(请注意,它返回的是计算命名函数表达式的结果,而不是表达式本身。)

以上是关于在 JavaScript 的上下文中说“将闭包分配给变量”是不是正确?的主要内容,如果未能解决你的问题,请参考以下文章

Django 在 JQuery AJAX 请求中说 is_ajax 是错误的

缠中说禅学习小结图谱

进阶学习js中的执行上下文

JavaScript原型

javascript之原型(prototype)

Javascript 在 if 语句中返回 false