闭包 (closure)是啥?

闭包
  闭包 (closure)是啥?
  闭包:基本概念
  闭包是可以包含自由(未绑定)变量的代码块;这些变量不是在这个代码块或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量的存在,相关变量引用没有释放)和为自由变量提供绑定的计算环境(作用域)。在 Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python 等语言中都能找到对闭包不同程度的支持。
  闭包的价值在于可以作为函数对象 或者匿名函数,对于类型系统而言这就意味着不仅要表示数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到变量中、作为参数传递给其他函数,最重要的是能够被函数动态地创建和返回。
  闭包的本质
  集合 <math>S<math> 是闭集当且仅当 <math>Cl(S)=S<math>。特别的,空集的闭包是空集,<math>X<math> 的闭包是 <math>X<math>。集合的交集的闭包总是集合的闭包的交集的子集(不一定是真子集)。有限多个集合的并集的闭包和这些集合的闭包的并集相等;零个集合的并集为空集,所以这个命题包含了前面的空集的闭包的特殊情况。无限多个集合的并集的闭包不一定等于这些集合的闭包的并集,但前者一定是后者的父集
  若 <math>A<math> 为包含 <math>S<math> 的 <math>X<math> 的子空间,则 <math>S<math> 在 <math>A<math> 中计算得到的闭包等于 <math>A<math> 和 <math>S<math> 在 <math>X<math> 中计算得到的闭包(<math>Cl_A(S) = A\cap Cl_X(S)<math>)的交集。特别的,<math>S<math> 在 <math>A<math> 中是稠密的,当且仅当 <math>A<math> 是 <math>Cl_X(S)<math> 的子集。
  闭包点
  对欧几里德空间的子集 S,x 是 S 的闭包点,若所有以 x 为中心的开球都包含 S 的点(这个点也可以是 x)。
  这个定义可以推广到度量空间 X 的任意子集 S。具体地说,对具有度量 d 的度量空间 X,x 是 S 的闭包点,若对所有 r > 0,存在 y 属于 S,使得距离 d(x, y) < r(同样的,可以是 x = y)。另一种说法可以是,x 是 S 的闭包点,若距离 d(x, S) := inf{d(x, s) : s 属于 S} = 0(这里 inf 表示下确界)。
  这个定义也可以推广到拓扑空间,只需要用邻域替代“开球”。设 S 是拓扑空间 X 的子集,则 x 是 S 的闭包点,若所有 x 邻域都包含 S 的点。注意,这个定义并不要求邻域是开的。
  极限点
  闭包点的定义非常接近极限点的定义。这两个定义之间的差别非常微小但很重要——在极限点的定义中,点 x 的邻域必须包含和 x 不同的集合的点。
  因此,所有极限点都是闭包点,但不是所有的闭包点都是极限点。不是极限点的闭包点就是孤点。也就是说,点 x 是孤点,若它是 S 的元素,且存在 x 的邻域,该邻域中除了 x 没有其他的点属于 S。
  对给定的集合 S 和点 x,x 是 S 的闭包点,当且仅当 x 属于 S,或 x 是 S 的极限点。
  集合的闭包
  集合 S 的闭包是所有 S 的闭包点组成的集合。S 的闭包写作 cl(S),Cl(S) 或 S−。集合的闭包具有如下性质:
  cl(S) 是 S 的闭父集。
  cl(S) 是所有包含 S 的闭集的交集。
  cl(S) 是包含 S 的最小的闭集。
  集合 S 是闭集,当且仅当 S = cl(S)。
  若 S 是 T 的子集,则 cl(S) 是 cl(T) 的子集。
  若 A 是闭集,则 A 包含 S 当且仅当 A 包含 cl(S)。
  有时候,上述第二或第三条性质会被作为拓扑闭包的定义。
  在第一可数空间(如度量空间)中,cl(S) 是所有点的收敛数列的所有极限。
  Perl中的闭包
  闭包 (closure)是个精确但又很难解释的电脑名词。在 Perl 里面,闭包是以 匿名函数的形式来实现,具有持续参照位于该函数范围之外的文字式变数值的能力。 这些外部的文字变数会神奇地保留它们在闭包函数最初定义时的值 (深连结)。
  如果一个程式语言容许函数递回另一个函数的话 (像 Perl 就是),闭包便具有意义。要注意的是,有些语言虽提供匿名函数的功能,但却无法正确处理闭包; Python 这个语言便是一例。如果要想多了解闭包的话,建议你去找本功能性程式 设计的教科书来看。Scheme这个语言不仅支援闭包,更鼓励多加使用。
  以下是个典型的产生函数的函数:
  sub add_function_generator {
  return sub { shift + shift };
  }
  $add_sub = add_function_generator();
  $sum = &$add_sub(4,5); # $sum现在是 9了
  闭包用起来就像是个函数样板,其中保留了一些可以在稍後再填入的空格。 add_function_generator() 所递回的匿名函数在技术上来讲并不能算是一个闭包, 因为它没有用到任何位在这个函数范围之外的文字变数。
  把上面这个例子和下面这个make_adder()函数对照一下,下面这个函数所递回的匿名函数中使用了一个外部的文字变数。这种指名外部函数的作法需要由 Perl递回一个适当的闭包,因此那个文字变数在匿名函数产生之时的值便永久地被锁进闭 包里。
  sub make_adder {
  my $addpiece = shift;
  return sub { shift + $addpiece };
  }
  $f1 = make_adder(20);
  $f2 = make_adder(555);
  这样一来&$f1($n) 永远会是 20加上你传进去的值$n ,而&$f2($n) 将 永远会是 555加上你传进去的值$n。$addpiece的值会在闭包中保留下来。
  闭包在比较实际的场合中也常用得到,譬如当你想把一些程式码传入一个函数时:
  my $line;
  timeout( 30, sub { $line = <STDIN> } );
  如果要执行的程式码当初是以字串的形式传入的话,即'$line = <STDIN>' ,那么timeout() 这个假想的函数在回到该函数被呼叫时所在的范围後便无法再撷取$list这个文字变数的值了。
  在Javascript中闭包(Closure)
  闭包的两个特点:
  1、作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态。
  2、一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
  例1。
  <script type="text/javascript">
  function sayHello2(name) {
  var text = 'Hello ' + name; // local variable
  var sayAlert = function() { alert(text); }
  return sayAlert;
  }
  var sy = sayHello2('never-online');
  sy();
  </script>

你可能感兴趣的:(JavaScript,python,Scheme,perl,lisp)