JavaScript中的“closure”是指什么?

73

我理解什么是闭包,但我有些难以理解术语 closure 的确切含义。我在许多网站上看到这个术语,但他们很少在实际定义上达成一致。

  • 它是保留在堆栈框架上的变量吗?
  • 它是被返回的函数吗?
  • 它是外部函数的作用域吗?
  • 它是内部(返回的)函数的作用域吗?
  • 也许它是保持变量在返回函数后仍留在堆栈框架中的概念吗?

有人能告诉我 closure 到底指的是什么吗?


8
+1是因为你提出了有用的问题。 - alex
在查看了半打的解释之后,这个链接对于分解主要考虑因素来说看起来相当不错:http://www.sitepoint.com/javascript-closures-demystified/ - Gene Bo
8个回答

45

来自JavaScript 闭包

两个简短的概括:

闭包是函数的局部变量 - 在函数返回后仍然存在,或者

闭包是一个堆栈帧,它在函数返回时不会被释放。(就像一个“堆栈帧”被malloc而不是在堆栈上!)

一个非常好的关于闭包的文章

JavaScript 闭包

"闭包"是一个表达式(通常是一个函数),它可以有自由变量和一个绑定这些变量的环境(“封闭”该表达式)。

一个闭包的简单解释是ECMAScript允许内部函数; 函数定义和函数表达式位于其他函数的函数体内。且那些内部函数可以访问其外部函数中的所有局部变量、参数和已声明的内部函数。当其中一个内部函数被访问并在其所在的函数之外执行时,就形成了一个闭包,因此闭包在外部函数返回后仍可以访问其外部函数的局部变量、参数和内部函数声明。这些局部变量、参数和函数声明(最初)具有它们在外部函数返回时的值,并且可以被内部函数交互地使用。

一个很好的示例在这里

JavaScript,时间来理解闭包


我已经写了一系列关于这个主题的文章,并配有图形解释。在这里阅读第4章和第5章:https://rahuldotout.wordpress.com/2011/05/15/professional-javascript-part-4-scopes-and-scope-chain/ - rahulmohan
闭包是函数的局部变量,在函数返回后仍然保持活动状态,或者它应该只是变量?还是函数?还是两者都有?因为在官方文档中,他们将内部函数称为闭包。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures - Asif Mushtaq

6

闭包是一种函数,它“持有”另一个作用域中的一个或多个引用。例如:

var myArrayOfFunctions = [];

for(var i = 0; i<3: i++)
{
    //Note how the function being defined uses i, 
    //where i lives in the parent's scope, this creates a closure
    myArrayOfFunctions[i] = function(a) { return a + i;}    
}

myArrayOfFunctions[0](5);   //Prints 8 WTF!
myArrayOfFunctions[1](5);   //8 again
myArrayOfFunctions[2](5);   //Well, this 8 was expected

这是因为当函数被“创建”时,它们不会复制i的值,而是保留对i的引用,所以当我们调用这些函数时,它们使用的是当前的i值,即3。 这里有一个图形化的解释。

4

对我来说,JS中的闭包允许您执行以下操作。
尽管"a"是在外部声明的,但它仍然在内部函数中添加到"b"时可用。

function adder(a){
  return function(b){
    return a + b;
  };
}
var add5 = adder(5);
alert( add5(10) );

如果想要深入了解JS闭包的用法,可以查看PURE库(一个JS模板引擎)的源代码


2
我知道闭包的作用,但是你的回答仍然没有真正澄清closure指的是什么。 - Andreas Grech
我喜欢这个例子,因为它是我知道的最简单的一个展示闭包是什么的例子,而且在学习函数式JS时对我来说是最有启发性的。 - Mic
你是从Stoyan Stefanov的JavaScript Patterns书中得到这个例子的吗? - Dan Beam
@Dan,不行。为什么?它完全一样啊? - Mic
是的,非常类似于柯里化部分,但我想这只是巧合。 - Dan Beam
2
我看了第83页......的确很相似。但是这本书的印刷时间比这个答案晚了将近一年 ;) - Mic

2
据我所知,闭包是在另一个函数内定义并超出父函数范围的函数。常见的例子是回调函数:
function delay_message(msg)
{
     setTimeout(function closure() { alert(msg); }, 1000);
}

在这种情况下,上述的“函数闭包”是在“delay_message”的代码块内定义的,但函数定义以及父函数的变量“msg”会超出“delay_message”函数调用的范围。

那么你的意思是闭包<i>就是</i>内部函数? - Andreas Grech
“闭包”是函数及其状态的组合。即,内部函数绑定到外部函数的一组局部变量。 - intgr
内部函数(函数闭包)是在解析时创建的,但此时还没有闭包。当 function delay_message 执行并将其状态绑定到 函数闭包 时,才创建闭包。 - intgr
一个匿名函数不是闭包。请不要继续传播这个错误的说法。 - Mike Axiak

2
考虑以下创建带有变量a和b的闭包的代码
closure=(function(){ 

    var a=3
    var b=5 

return  function(operation){ 
          return operation(a,b)
      }
 }())


// The variables a and b are now part of the closure (They are retained even after the outer function returns)


closure(function(x,y){return x+y})  // outputs 8

closure(function(x,y){return x*y}) // outputs 15`

这个特定的闭包现在可以接受任何操作变量a和b的函数。

1

本质上,闭包是一个函数体,在其本地环境中关闭其标识符(变量)。


1
闭包是从嵌套函数声明或函数表达式(即lambda表达式)创建的函数值,其主体包含对在外部(但不是全局)作用域中声明的一个或多个变量的引用。

0

闭包指的是一个包含另一个函数(内部函数)的函数(外部函数)。

闭包用于保护数据。

下面提供的视频链接演示了闭包的使用:

https://www.youtube.com/watch?v=w1s9PgtEoJs


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