在JavaScript中,每个函数都是闭包吗?

5

我一直在阅读关于JS中的闭包的相关内容。我参考了多种指南,例如这个https://medium.freecodecamp.org/javascript-closures-simplified-d0d23fa06ba4

然而,我仍有一个问题。闭包是否仅适用于一阶函数(返回函数的函数)?或者,任何函数都是闭包吗? 实际上唯一不同的区别在于某些未嵌套的函数,其中3个作用域链之一(外部函数的作用域)可能为空但它仍然存在。


我们可以说,无论在哪里使用函数的引用来使用该函数作用域,我们都在那里使用闭包。而要使用该引用,我们要么从父函数返回对象,要么返回另一个函数。 - ganesh phirke
2个回答

3

闭包是通过调用函数来创建的;函数本身不是闭包。从概念上讲,每次函数调用都会隐式地产生一个新的闭包。对于某些函数,闭包是短暂的,并在函数返回后立即消失:

function add2(n) {
  return n + 2;
}

那个函数只返回一个数字;在函数调用创建的闭包中,没有任何东西可以引用它,所以闭包消失了,你只剩下了返回值。

当一个函数返回某些具有一个或多个“钩子”进入函数调用时创建的本地环境的内容时,闭包变得有趣。(函数还可以通过修改全局环境来公开闭包。)所以这个函数:

function addn(addend) {
  return function(n) {
    return n + addend;
  }
}

返回的函数引用了外部函数的参数,因此将闭包暴露出来。

我无法想象一个普通函数如何暴露一个闭包,而不涉及一个或多个函数引用局部上下文(参数、变量)。 (生成器函数很有趣,因为 yield 总是返回一些暴露闭包的东西,我想。)


请注意,在第一段中,我写了“从概念上讲”——如果运行时发现闭包无法公开,则可以自由优化事物。 - Pointy
在最后一段中,我考虑的是一个返回仅涉及本地变量等引用的对象(或对象结构)的函数;我想不出这需要闭包本身保持“活动”的原因。 - Pointy

1
一个闭包是函数和该函数声明所在的词法环境的组合。
例如,
 function greet(Say){
   return (
          function(name){
             console.log(Say + ' ' + name);
          }
   )
}

现在我可以做这样的事情,
greet('Hi')('Alex')

这行代码将返回字符串'Hi Alex'
现在我要做这样的事情,
var sayGreet = greet('Hi');

如果我使用console.log(sayGreet),它将是一个函数。 现在告诉我,这个sayGreet变量是在哪里定义的?它是在全局级别定义的,或者换句话说,是在全局执行上下文中定义的。 现在让我们做一下,
sayGreet('Alex')

在这个sayGreet函数内部,我们有一个console.log(Say + " " + name)。我们知道name是Alex,但Say呢?此时没有Say的任何迹象,因为greet函数已经执行完毕并返回了一个函数。

尽管JavaScript仍然可以引用Say值,即使它已经完成执行。这个Say值只能被内部函数或嵌套函数访问。

这就是闭包。单个函数不能成为闭包。也应该有一个外部词法环境。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接