闭包
目录
闭包的基本概念
闭包的价值
闭包的本质
Perl中的闭包
在Javascript中闭包(Closure)
在Python中的闭包(Closure)
在离散中“关系”的闭包(Closure)
<script type="text/javascript"></script>
闭包的基本概念
闭包是可以包含自由(未绑定)变量的代码块;这些变量不是在这个代码块或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量的存在,相关变量引用没有释放)和为自由变量提供绑定的计算环境(作用域)。在 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)
一、什么是闭包? “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。 相信很少有人能直接看懂这句话,因为他描述的太学术。我想用如何在Javascript中创建一个闭包来告诉你什么是闭包,因为跳过闭包的创建过程直接理解闭包的定义是非常困难的。看下面这段代码: function a(){ var i=0; function b(){ alert(++i); } return b; } var c = a(); c(); 这段代码有两个特点: 1、函数b嵌套在函数a内部; 2、函数a返回函数b。 这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说: 当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。 我猜想你一定还是不理解闭包,因为你不知道闭包有什么作用,下面让我们继续探索。 二、闭包有什么作用? 简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。 在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。 那 么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。(关于Javascript的垃圾回收机制将在后面详细介绍) 三、闭包内的微观世界 如 果要更加深入的了解闭包以及函数a和嵌套函数b的关系,我们需要引入另外几个概念:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。 1、当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain中只有window对象。 2、当函数a执行的时候,a会进入相应的执行环境(excution context)。 3、在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。 4、然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。 5、下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。 6、最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。 到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是说b可以访问到a中定义的所有变量和函数。函数b被c引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。 当函数b执行的时候亦会像以上步骤一样。因此,执行时b的作用域链包含了3个对象:b的活动对象、a的活动对象和window对象,如下图所示: 如图所示,当在函数b中访问一个变量的时候,搜索顺序是先搜索自身的活动对象,如果存在则返回,如果不存在将继续搜索函数a的活动对象,依 次查找,直到找到为止。如果整个作用域链上都无法找到,则返回undefined。如果函数b存在prototype原型对象,则在查找完自身的活动对象 后先查找自身的原型对象,再继续查找。这就是Javascript中的变量查找机制。 四、闭包的应用场景 1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。 2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。 以上两点是闭包最基本的应用场景,很多经典案例都源于此。 五、Javascript的垃圾回收机制 在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
在Python中的闭包(Closure)
学过Java GUI编程的人都知道定义匿名内部类是注册监听等处理的简洁有效手段,闭包的定义方式有点类似于这种匿名内部类, 但是闭包的作用威力远远超过匿名内部类,这也是很多流行动态语言选择闭包的原因,相信你在JavaScript中已经了解它的神奇功效了。
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。 简单闭包的例子: 下面是一个使用闭包简单的例子,模拟一个计数器,通过将整型包裹为一个列表的单一元素来模拟使看起来更易变:
代码格式较重要
函数counter()所作的唯一一件事就是接受一个初始化的值来计数,并将该值赋给列表count成员,然后定义一个内部函数incr()。通过内部函数使用变量count,就创建了一个闭包。最魔法的地方是counter()函数返回一个incr(),一个可以调用的函数对象。 运行: >>> c = counter(5) >>> type(c) <type 'function'> >>> print c() 6 >>> print c() 7 >>> c2 = counter(99) 100 >>> print c() 8
在离散中“关系”的闭包(Closure)
离散中,一个关系R的闭包,是指加上最小数目的有序偶而形成的具有自反性,对称性或传递性的新的有序偶集,此集就是关系R的闭包
分享到:
相关推荐
### 关系闭包的计算 #### 实验背景与目的 在计算机科学与数学领域中,关系闭包是一种重要的概念,特别是在图论与数据库理论中有着广泛的应用。...这对于深入学习计算机科学的相关领域具有重要的意义。
在计算机科学和图论中,自反闭包是与关系理论相关的概念,特别是在布尔代数和图的子结构分析中。自反闭包是指给定一个关系R,将其扩展为包含所有起点到自身的元素对,即对于每一个元素a,都有(a, a)属于自反闭包。这...
内存泄露和闭包是两个关键概念,它们紧密关联并可能对程序性能产生重大影响。 内存泄露是指程序在不再需要某些数据时,未能释放这些数据所占用的内存。在JavaScript中,由于其自动垃圾回收(Garbage Collection, GC...
原子闭包系统、原子闭包算子以及原子全蕴含系统是数理逻辑、抽象代数以及数学基础理论中的概念。在本篇文章中,作者杨海建、李庆国和何霞辉对这些概念进行了深入...文章的发表,对于推动相关领域的研究具有重要意义。
JavaScript中的闭包是一种高级特性,对于初学者来说可能有些...实践中,多编写闭包相关的代码,结合实例去体会它的功能和优势,将有助于更好地掌握这一核心概念。同时,不要忘记在使用闭包时注意内存管理和性能优化。
本书涵盖了闭包相关的各个方面,包括但不限于闭包的基本概念、实现原理、性能优化技巧以及如何利用闭包构建高效可靠的JavaScript应用程序等内容。本书旨在为JavaScript开发者提供一个全面深入的闭包学习资源,无论你...
具体来说,闭包是由函数及与其相关的引用环境组合而成的一个整体。 #### 二、闭包的组成 闭包主要由以下几个部分组成: - **函数**:闭包的核心是一个函数。 - **环境**:函数运行时所处的作用域环境。 - **外部...
在离散数学中,二元关系是一个非常基础且重要的概念,它描述了集合中的元素对之间的相互作用。二元关系的闭包运算则是研究这些关系...无论是理论探索还是实际应用,这一主题都是离散数学和相关领域中不可或缺的一部分。
闭包可以捕获和存储它所在上下文中的常量和变量,这使得它们非常适合用于异步操作、回调函数或者封装一系列相关操作。本教程将深入探讨如何在iOS应用中使用闭包进行值传递。 闭包的基本语法: 闭包的语法通常由花...
具体来说,闭包是由函数及其相关的引用环境组合而成的实体。 例如: ```javascript function f1() { var a = 10; function f2() { alert(a); // 输出 10 } return f2; } var fn = f1(); // f1 返回了 f2 ...
这个概念源于数学,但在编程语言中,它通常与函数和作用域相关。在这个“山东大学三元闭包实验”中,我们看到使用R语言来实现这一概念。 首先,让我们深入理解“三元闭包”。在图论中,三元闭包是指在关系R上的一种...
1. 定义一个包含ZTree实例、节点数据和相关方法的闭包。 2. 在闭包内初始化ZTree,加载初始数据,并创建需要的私有方法,如增删改查和排序。 3. 对外提供公共接口,这些接口将调用闭包内的私有方法,以操作ZTree节点...
例如,自反闭包确保集合内的每个元素都与自身相关联,传递闭包确保如果A与B相关且B与C相关,则A与C也相关。 2. **自反闭包**:自反闭包是通过添加所有可能的自反关系来构建的,即对于任何元素x,都有(x, x)属于闭包...
### 闭包作用域 #### 一、JavaScript闭包简介 在JavaScript中,闭包(Closure)是一个非常重要的概念,它允许一个函数访问并操作其外部作用域中的变量,即使该函数在其外部作用域之外被调用。这种特性使得闭包成为...
如果不再需要闭包,应确保将其设置为 `null` 来释放引用,让垃圾回收器可以回收相关资源。 总之,闭包是JavaScript中一种强大的工具,它允许我们创建持久化的、私有的变量状态,实现模块化和数据封装。理解并熟练...
自反闭包是指关系矩阵中的主对角线全部置为1,即每个元素在关系中都与自己相关。这种闭包可以用于判断关系是否满足自反性质。例如,在社交网络中,如果两个用户之间存在关注关系,那么在关系矩阵中,他们之间的元素...
闭包是函数和与其相关的引用环境(即变量的值)的组合,这个组合使得函数能够记住它被定义时的作用域,即使在函数被调用时该作用域已经不再存在。下面我们将详细讨论闭包的概念、工作原理以及如何在不同的编程语言中...
在这个例子中,`closure`是一个闭包,它接受一个`String`类型的参数`selectedOption`,并在大括号内部执行相关操作。 对比Objective-C(OC),OC中的 Blocks 是一种类似的概念,但语法和使用方式略有不同。OC中的...
在探讨闭包之前,我们先来了解几个相关的概念:作用域、变量作用域以及函数的作用域链。这些是理解闭包的基础。 - **作用域(Scope)**:指的是变量或者函数可以被访问的范围。 - **变量作用域**:指变量在其定义...