精华内容
下载资源
问答
  • 什么是闭包

    2021-01-12 22:59:06
    闭包就是能够读取其他函数内部变量的62616964757a686964616fe58685e5aeb931333433626565函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质...

    闭包就是能够读取其他函数内部变量的62616964757a686964616fe58685e5aeb931333433626565函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

    简单介绍

    闭包包含自由(未绑定到特定对象)变量,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。在PHP、Scala、Scheme、Common

    Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift

    以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。

    本质

    集合 S 是闭集当且仅当 Cl(S)=S(这里的cl即closure,闭包)。特别的,空集的闭包是空集,X 的闭包是 X。集合的交集的闭包总是集合的闭包的交集的子集(不一定是真子集)。有限多个集合的并集的闭包和这些集合的闭包的并集相等;零个集合的并集为空集,所以这个命题包含了前面的空集的闭包的特殊情况。无限多个集合的并集的闭包不一定等于这些集合的闭包的并集,但前者一定是后者的父集。

    若 A 为包含 S 的 X 的子空间,则 S 在 A 中计算得到的闭包等于 A 和 S 在 X 中计算得到的闭包(Cl_A(S) = A ∩ Cl_X(S))的交集。特别的,S在 A 中是稠密的,当且仅当 A 是 Cl_X(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) 是所有点的收敛数列的所有极限。

    举例说明

    闭包 (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 = });

    如果要执行的程式码当初是以字串的形式传入的话,即'$line = ' ,那么timeout() 这个假想的函数在回到该函数被呼叫时所在的范围后便无法再截取$line这个文字变数的值了。

    语法结构

    Groovy

    闭包(Closure)是Java所不具备的语法结构(JAVA8增加了对闭包的支持)。闭包就是一个代码块,用“{ }”包起来。此时,程序代码也就成了数据,可以被一个变量所引用(与C语言的函数指针比较类似)。闭包的最典型的应用是实现回调函数(callback)。Groovy的API大量使用闭包,以实现对外开放。闭包的创建过程很简单,例如:

    { 参数 ->

    代码...

    }

    参考下面的例子代码,定义了c1和c2两个闭包,并对它们进行调用:

    def c1 = { println it }

    def c2 = { text -> println text }

    c1.call("content1") //用call方法调用闭包

    c2("content2") //直接调用闭包

    “->;”之前的部分为闭包的参数,如果有多个参数,之间可用逗号分割;“->;”之后的部分为闭包内的程序代码。如果省略了“->;”和它之前的部分,此时闭包中代码,可以用名为“it”的变量访问参数。

    闭包的返回值和函数的返回值定义方式是一样的:如果有return语句,则返回值是return语句后面的内容;如果没有return语句,则闭包内的最后一行代码就是它的返回值。[2]

    Lua

    当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征在lua中我们称作词法定界。虽然这看起来很清楚,事实并非如此,词法定界加上第一类函数在编程语言里是一个功能强大的概念,很少语言提供这种支持。

    下面看一个简单的例子,假定有一个学生姓名的列表和一个学生名和成绩对应的表;想根据学生的成绩从高到低对学生进行排序,可以这样做:

    names = {"Peter","Paul","Mary"}

    grades = {Mary = 10,Paul = 7,Peter = 8}

    table.sort(names,function (n1,n2)

    return grades[n1] > grades[n2] -- compare the grades

    end)

    假定创建一个函数实现此功能:

    function sortbygrade (names,grades)

    table.sort(names,function (n1,n2)

    return grades[n1] > grades[n2] --compare the grades

    end)

    Scheme

    其他编程的语言主要采用的是闭包的第二种意义(一个与闭包毫不相干的概念):闭包也算一种为表示带有自由变量的过程而用的实现技术。但Scheme的术语“闭包”来自抽象代数。在抽象代数里,一集元素称为在某个运算(操作)之下封闭,如果将该运算应用于这一集合中的元素,产生出的仍然是该集合里的元素。

    用Scheme的序对举例,为了实现数据抽象,Scheme提供了一种称为序对的复合结构。这种结构可以通过基本过程cons构造出来。过程cons取两个参数,返回一个包含这两个参数作为其成分的复合数据对象。请注意,一个序对也算一个数据对象。进一步说,还可以用cons去构造那种其元素本身就是序对的序对,并继续这样做下去。

    (define x (cons 1 2)) //构造一个x序对,由1,2组成

    (define y (cons 3 4))

    (define z (cons x y))

    Scheme可以建立元素本身也算序对的序对,这就是表结构得以作为一种表示工具的根本基础。我们将这种能力称为cons的闭包性质。一般说,某种组合数据对象的操作满足闭包性质,那就是说,通过它组合起数据对象得到的结果本身还可以通过同样的操作再进行组合。闭包性质是任何一种组合功能的威力的关键要素,因为它使我们能够建立起层次性结构,这种结构由一些部分构成,而其中的各个部分又是由它们的部分构成,并且可以如此继续下去。

    创建

    在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的垃圾回收机制不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。

    在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。

    那 么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被回收。

    例子

    例1

    模拟私有变量:

    function Counter(start){

    var count = start;

    return{

    increment:function(){

    count++;

    },

    get:function(){

    return count;

    }

    }

    }

    var foo =Counter(4);

    foo.increment();

    foo.get();// 5

    这里,Counter 函数返回两个闭包,函数 increment 和函数 get。 这两个函数都维持着对外部作用域 Counter 的引用,因此总可以访问此作用域内定义的变量count。

    objective c的闭包(block)

    objective c

    中的的闭包,是通过block实现的。Apple在C,Objective-C和C++中扩充了Block这种文法的,并且在GCC4.2中进行了支持。你可以把它理解为函数指针,匿名函数,闭包,lambda表达式,这里暂且用块对象来表述,因为它们之间还是有些许不同的。

    如果以内联方式使用块对象,则无需声明。块对象声明语法与函数指针声明语法相似,但是块对象应使用脱字符(^)而非星号指针 (*)。下面的代码声明一个aBlock变量,它标识一个需传入三个参数并具有float返回值的块。

    float (^aBlock)(const int*, int, float);

    例2

    下面是一个使用闭包简单的例子,模拟一个计数器,通过将整型包裹为一个列表的单一元素来模拟使看起来更易变:

    函数counter()所作的唯一一件事就是接受一个初始化的值来计数,并将该值赋给列表count成员,然后定义一个内部函数incr()。通过内部函数使用变量count,就创建了一个闭包。最魔法的地方是counter()函数返回一个incr(),一个可以调用的函数对象。

    运行:

    >>> c = counter⑸

    >>> type(c)

    >>> print c()6

    >>> print c()

    7

    >>> c2 = counter(99)

    100

    >>> print c()

    8

    微观世界

    如 果要更加深入的了解闭包以及函数a和嵌套函数b的关系,我们需要引入另外几个概念:函数的执行环境(execution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。

    1、当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain中只有window对象。

    2、当函数a执行的时候,a会进入相应的执行环境(execution 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中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。

    匿名内部

    在Python中的闭包(Closure)

    学过Java GUI编程的人都知道定义匿名内部类是注册监听等处理的简洁有效手段,闭包的定义方式有点类似于这种匿名内部类,

    但是闭包的作用威力远远超过匿名内部类,这也是很多流行动态语言选择闭包的原因,相信你在JavaScript中已经了解它的神奇功效了。

    度量空间

    对欧几里德空间的子集 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 的点。注意,这个定义并不要求邻域是开的。

    离散数学

    离散数学中,一个关系R的闭包,是指加上最小数目的有序偶而形成的具有自反性,对称性或传递性的新的有序偶集,此集就是关系R的闭包。

    设R是集合A上的二元关系,R的自反(对称、传递)闭包是满足以下条件的关系R':

    (i)R'是自反的(对称的、传递的);

    (ii)R'⊇R;

    (iii)对于A上的任何自反(对称、传递)关系R",若R"⊇R,则有R"⊇R'。

    R的自反、对称、传递闭包分别记为r(R)、s(R) 和t(R)。

    性质1

    集合A上的二元关系R的闭包运算可以复合,例如:

    ts(R)=t(s(R))

    表示R的对称闭包的传递闭包,通常简称为R的对称传递闭包。而tsr(R)则表示R的自反对称传递闭包。

    性质2

    设R是集合A上的二元关系,则有

    (a)如果R是自反的,那么s(R)和t(R)也是自反的;

    (b)如果R是对称的,那么r(R)和t(R)也是对称的;

    (c)如果R是传递的,那么r(R)也是传递的。

    性质3

    设R是集合A上的二元关系,则有

    (a)rs(R)=sr(R);

    (b)rt(R)=tr(R);

    (c)ts(R)⊇ st(R)。

    使用注意点

    (1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    (2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果把父函数当作对象(object)使用,把闭包当作它的公用方法(Public

    Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    点集拓扑系列

    展开全文
  • 我是怎样理解闭包

    2021-01-12 22:59:05
    什么是闭包最近更新: 2014年02月28日14:39:58 (最新地址)一、一个问题例一:假设要写动态生成HTML的函数,HTML有一部分是固定的。方案①function buildHtml(args) {var template = ['','','','',''];template[1] = ...

    什么是闭包

    最近更新: 2014年02月28日14:39:58 (最新地址)

    一、一个问题

    例一:假设要写动态生成HTML的函数,HTML有一部分是固定的。

    方案①

    function buildHtml(args) {

    var template = ['

    ',

    '',

    '

    ',

    '',

    '

    '];

    template[1] = args[0];

    template[3] = args[1];

    return template.join('');

    }

    执行函数时,先定义template,执行完销毁template,多次执行就多次重复定义和销毁,这样不好,考虑把template变量放到生成Html函数的外面,改造后成了这样:

    方案②

    //...

    var template = ['

    ',

    '',

    '

    ',

    '',

    '

    '];

    function buildHtml(args){

    template[1] = args[0];

    template[3] = args[1];

    return template.join('');

    }

    //...这里可以调用上面的代码

    当其它页面或模块也需要这个生成Html函数时,拷贝相关代码时,要保证template变量名和buildHtml函数名不能与已有的命名空间冲突,还可以这样实现:

    方案③

    //...

    buildHtml.template = ['

    ',

    '',

    '

    ',

    '',

    '

    '];

    function buildHtml(args){

    var template = buildHtml.template;

    template[1] = args[0];

    template[3] = args[1];

    return template.join('');

    }

    //...这里可以调用上面的代码

    方案④

    var buildHtml = (function(){

    var template = ['

    ',

    '',

    '

    ',

    '',

    '

    '];

    return function(args){

    template[1] = args[0];

    template[3] = args[1];

    return template.join('');

    }

    })();

    方案3和方案4都只用考虑其中一个变量名是否冲突。方案4 结构更紧凑,且template私有化,外面无法访问,这里就用到了闭包。

    二、闭包定义

    在一个函数内定义一个函数,并且这个内部函数可以在外面访问,这时候就形成了闭包。

    方案④是立执行函数,函数内部变量template在函数执行完后,仍保留在内存中,等待内部函数调用,当buildHtml=null时,才被内存回收。同理,当外部函数执行完毕后,若内部函数就不能访问了,就不形成闭包。

    那怎样实现访问内部函数,通过return将内部引用暴露给外部?将内部函数赋给全局变量?全局变量可以是未经var声明而即时产生的,也可能是传入的实参,如例四。

    例二:

    function wrapFns (){

    var arr = [];

    for(var i = 10;i--;){

    arr[i] = function(){

    return i;

    }

    }

    return arr;

    }

    var fns = wrapFns();

    console.log(fns[10]()); // 值是多少?

    内部函数对象,通过隐藏属性引用[[scope]],访问指向的作用域链各个活动对象。在这里,第一个活动对象就是wrapFns的上下文,所以当执行wrapFns时,访问到的i已经为0了,输出值是:0。

    三、闭包的内部机制

    为什么函数的局部变量会被维持?闭包的内部机制是怎样的?函数嵌套很多层时的闭包是怎样的?

    ①函数也是对象,有[[scope]]属性(只能通过JavaScript引擎访问),指向函数定义时的执行环境上下文。

    ②假如A是全局的函数,B是A的内部函数。执行A函数时,当前执行环境的上下文指向一个作用域链。作用域链的第一个对象是当前函数的活动对象(this、参数、局部变量),第二个对象是全局window。

    ③当执行代码运行到B定义地方, 设置函数B的[[scope]]属性指向执行环境的上下文作用域链。

    ④执行A函数完毕后,若内部函数B的引用没外暴,A函数活动对象将被Js垃圾回收处理;反之,则维持,形成闭包。

    ⑤调用函数B时,JavaScript引擎将当前执行环境入栈,生成新的执行环境,新的执行环境的上下文指向一个作用域链,由当前活动对象+函数B的[[scope]]组成,链的第一个对象是当前函数的活动对象(this、参数、局部变量组成),第二个活动对象是A函数产生的,第三个window。

    ⑥B函数里面访问一个变量,要进行标志符解析(JavaScript原型也有标识符解析),它从当前上下文指向的作用域链的第一个对象开始查找,找不到就查找第二个对象,直到找到相关值就立即返回,如果还没找到,报undefined错误。

    ⑦当有关A函数的外暴的内部引用全部被消除时,A的活动对象才被销毁。

    如果B函数引用给外部,它的[[scope]]中的活动对象,比如父函数A的活动对象会被维持,当B函数再次调用时,仍然可以读写,这样可实现数据的本地存储,并且只能由你这个接口访问。

    作用域链临时变更情况

    如使用with(obj){},try{}catch(obj){},会将obj添加到作用域链的首部,其它活动对象相应后移一位,直到with结束。

    使用Function定义的函数对象,函数对象的[[scope]]属性置为window。

    四、闭包的应用

    1、封装插件

    (function(window,undefined){

    window.ymPrompt = {}; //

    })(window);

    2、保存私有属性

    var factorial = (function () {

    var cache = [];

    return function (num) {

    if (!cache[num]) {

    if (num == 0) {

    cache[num] = 1;

    }

    cache[num] = num * factorial(num - 1);

    }

    return cache[num];

    }

    })();

    五、那些不经意间用了闭包

    1. Demo1

    var object = {

    name:"My Object",

    getNameFunc: function(){

    var that = this;

    return function(){

    return that.name;

    };

    }

    };

    console.log(object.getNameFunc()());// My Object

    2. Demo2

    (function(w,undefined){

    var temp = ['a'],

    domRefer = document.getElementById('');

    domRefer.addEventListener('click',function(event){

    //...

    },false);

    })(window)

    六、使用闭包注意

    1、只有需要时才使用闭包,闭包会导致一些东西常驻内存。

    一个这样的构造函数

    function Construt(){

    var bb;

    this.aa = '1';

    this.fun1 = function(){};

    this.fun2 = function(){};

    }

    在fun1和fun2中没用到bb,就不要用闭包。

    function Construt(){

    this.aa = '1';

    }

    Construt.prototype={

    constructor:Construt,

    fun1:function(){},

    fun2:function(){}

    }

    2、 使用闭包时,可以将不需继续调用局部变量在父函数末尾置为null。

    七、最后一点

    一个函数,能访问什么变量,看的是定义在什么地方,而不是执行的位置。

    // 外部定义的函数,在一函数中被返回并执行,执行时,并无闭包功能

    function inside() {

    return x;

    }

    function outside(){

    var x = 1;

    return inside;

    }

    var xx = outside()();

    想知道结果,点击链接,打开调试器即可。

    如有新的内容,会不断更新...

    展开全文
  • 关于闭包

    2021-01-12 22:59:08
    卡尔维诺中文站留言板这个帖子专门用作卡尔维诺中文站的留言板,...学习Javascript闭包(Closure) - 阮一峰的网络日志a.bshareDiv,#bsPanel,#bsMorePanel,#bshareF{border:none;background:none;padding:0;margin:0...

    卡尔维诺中文站留言板

    这个帖子专门用作卡尔维诺中文站的留言板,欢迎大家留言和提问。...

    阮一峰

    2007-01-04T18:54:26+08:00

    -->学习Javascript闭包(Closure) - 阮一峰的网络日志

    a.bshareDiv,#bsPanel,#bsMorePanel,#bshareF{border:none;background:none;padding:0;margin:0;font:12px Helvetica,Calibri,Tahoma,Arial,宋体,sans-serif;line-height:14px;}#bsPanel div,#bsMorePanel div,#bshareF div{display:block;}.bsRlogo .bsPopupAwd,.bsRlogoSel .bsPopupAwd,.bsLogo .bsPopupAwd,.bsLogoSel .bsPopupAwd{line-height:16px !important;}a.bshareDiv div,#bsFloatTab div{*display:inline;zoom:1;display:inline-block;}a.bshareDiv img,a.bshareDiv div,a.bshareDiv span,a.bshareDiv a,#bshareF table,#bshareF tr,#bshareF td{text-decoration:none;background:none;margin:0;padding:0;border:none;line-height:1.2}a.bshareDiv span{display:inline;float:none;}div.buzzButton{cursor:pointer;font-weight:bold;}.buzzButton .shareCount a{color:#333}.bsStyle1 .shareCount a{color:#fff}span.bshareText{white-space:nowrap;}span.bshareText:hover{text-decoration:underline;}a.bshareDiv .bsPromo,div.bshare-custom .bsPromo{display:none;position:absolute;z-index:100;}a.bshareDiv .bsPromo.bsPromo1,div.bshare-custom .bsPromo.bsPromo1{width:51px;height:18px;top:-18px;left:0;line-height:16px;font-size:12px !important;font-weight:normal !important;color:#fff;text-align:center;background:url(http://static.bshare.cn/frame/images/bshare_box_sprite2.gif) no-repeat 0 -606px;}div.bshare-custom .bsPromo.bsPromo2{background:url(http://static.bshare.cn/frame/images/bshare_promo_sprite.gif) no-repeat;cursor:pointer;}

    .bsBox{display:none;z-index:100000001;font-size:12px;background:url(http://static.bshare.cn/frame/images//background-opaque-dark.gif) !important;padding:6px !important;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;}.bsClose{_overflow:hidden;cursor:pointer;position:absolute;z-index:10000000;color:#666;font-weight:bold;font-family:Helvetica,Arial;font-size:14px;line-height:20px;}.bsTop{color:#666;background:#f2f2f2;height:24px;line-height:24px;border-bottom:1px solid #e8e8e8;}.bsTop span{float:left;}.bsFrameDiv,#bsMorePanel{border:none;background:#fff;}.bsReturn{float:right;*margin-right:20px;margin-right:36px;text-align:right;cursor:pointer;line-height:24px;color:#666;opacity:0.5;}#bsReturn:hover{text-decoration:underline;opacity:1;}

    div.bsClear{clear:both;height:0;line-height:0;overflow:hidden;font-size:0;}.bsSearchDiv{padding:5px 15px;background-color:#fafafa;}.bFind-wrapper-top{background:#fff;border-color:#ccc #aaa #aaa #ccc;border-style:solid;border-width:1px;height:16px;padding:4px;margin:0;}.bFind-wrapper-top input{padding:0 !important;border:none !important;box-shadow:none !important;line-height:16px !important;}.bFind-placeholder{background:url("http://static.bshare.cn/css/images/search-icon.gif") no-repeat;display:block;float:left;height:16px;width:16px;}.bFind{background:none;border:none;float:left;font-size:11px !important;height:16px !important;margin-left:3px;outline:none;padding:0;width:400px;}.bsPlatDiv{height:322px;background:#fff;overflow:auto;padding:0 15px;}#bsLogoList{display:block;list-style:none;overflow:hidden;margin:0;padding:0;}#bsLogoList li{float:left;display:inline-block;width:71px;text-align:center;font-size:12px;height:80px;margin:0 !important;}#bsLogoList .bsPlatIcon{cursor:pointer;display:block !important;text-align:center;}#bsLogoList .bsPlatImg{width:32px;height:32px;border:none !important;display:inline-block;}#bsLogoList .bsPlatImg:hover{-moz-border-radius:7px;-webkit-border-radius:7px;border-radius:7px;box-shadow:0 0 15px #a7a8ac;}#bsLogoList .bsPlatName{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-align:center;color:#333 !important;margin-top:2px;line-height:140%;*width:70px;}#bsLogoList .bsPromoM{text-align:center;}.bsFooterDiv{height:24px;line-height:24px;padding:0 15px;border-top:1px solid #e8e8e8;background:#f2f2f2;text-align:right;}a.bsLogoLink{color:#666;}.bsLogoLink:hover{text-decoration:underline;}.bsPromoM{background:url(http://static.bshare.cn/frame/images//bshare_box_sprite2.gif) no-repeat top left;}.bsNew,.bsHot,.bsRec,.bsAwd{background-position:0 -552px;width:19px;margin:5px auto 1px;line-height:16px;height:18px;font-size:12px;color:#fff;overflow:hidden;}.bsNew{background-position:0 -570px;}.bsRec{width:30px;background-position:0 -588px;}.bsAwd{background:url(http://static.bshare.cn/frame/images//promot/promote.gif) no-repeat;}

    a.bsSiteLink{text-decoration:none;color:#666;}a.bsSiteLink:hover{text-decoration:underline;}a.bshareDiv{overflow:hidden;height:16px;line-height:18px;font-size:14px;color:#333;padding-left:0;}a.bshareDiv:hover{text-decoration:none;}div.bsTitle{padding:0 8px;border-bottom:1px solid #e8e8e8;color:#666;background:#f2f2f2;text-align:left;}div.buzzButton{cursor:pointer;}div.bsRlogo,div.bsRlogoSel{width:68px;float:left;margin:0;padding:2px 0;}div.bsRlogo a,div.bsRlogoSel a{float:left;}div.bsLogo,div.bsLogoSel{float:left;width:111px;text-align:left;height:auto;padding:2px 4px;margin:2px 0;white-space:nowrap;overflow:hidden;}div.bsLogoSel,div.bsRlogoSel{border:1px solid #ddd;background:#f1f1f1;}div.bsLogo,div.bsRlogo{border:1px solid #fff;background:#fff;}div.bsLogo a,div.bsLogoSel a{display:block;height:16px;line-height:16px;padding:0 0 0 24px;text-decoration:none;float:left;overflow:hidden;}div.bsLogoSel a,div.bsRlogoSel a{color:#000;border:none;}div.bsLogo a,div.bsRlogo a{color:#666;border:none;}div.bsLogoLink{width:121px;overflow:hidden;background:#FFF;float:left;margin:3px 0;}#bsLogin{float:right;text-align:right;overflow:hidden;height:100%;}#bsPanel{position:absolute;z-index:100000000;font-size:12px;width:258px;background:url(http://static.bshare.cn/frame/images/background-opaque-dark.png) !important;padding:6px !important;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;}div.bsClear{clear:both;height:0;line-height:0;font-size:0;overflow:hidden;}div.bsPopupAwd{background:url(http://static.bshare.cn/frame/images//bshare_box_sprite2.gif) no-repeat top left;background-position:0 -624px;width:18px;padding-left:3px;text-align:center;float:left;margin-left: 2px;height:15px;font-size:12px;color:#fff;overflow:hidden;}div.bsRlogo .bsPopupAwd,div.bsRlogoSel .bsPopupAwd{float:left;margin:5px 0 0 -14px;}

    a.bsSiteLink{text-decoration:none;color:#666;}a.bsSiteLink:hover{text-decoration:underline;}a.bshareDiv{overflow:hidden;height:16px;line-height:18px;font-size:14px;color:#333;padding-left:0;}a.bshareDiv:hover{text-decoration:none;}div.bsTitle{padding:0 8px;border-bottom:1px solid #e8e8e8;color:#666;background:#f2f2f2;text-align:left;}div.buzzButton{cursor:pointer;}div.bsRlogo,div.bsRlogoSel{width:68px;float:left;margin:0;padding:2px 0;}div.bsRlogo a,div.bsRlogoSel a{float:left;}div.bsLogo,div.bsLogoSel{float:left;width:111px;text-align:left;height:auto;padding:2px 4px;margin:2px 0;white-space:nowrap;overflow:hidden;}div.bsLogoSel,div.bsRlogoSel{border:1px solid #ddd;background:#f1f1f1;}div.bsLogo,div.bsRlogo{border:1px solid #fff;background:#fff;}div.bsLogo a,div.bsLogoSel a{display:block;height:16px;line-height:16px;padding:0 0 0 24px;text-decoration:none;float:left;overflow:hidden;}div.bsLogoSel a,div.bsRlogoSel a{color:#000;border:none;}div.bsLogo a,div.bsRlogo a{color:#666;border:none;}div.bsLogoLink{width:121px;overflow:hidden;background:#FFF;float:left;margin:3px 0;}#bsLogin{float:right;text-align:right;overflow:hidden;height:100%;}#bsPanel{position:absolute;z-index:100000000;font-size:12px;width:258px;background:url(http://static.bshare.cn/frame/images/background-opaque-dark.png) !important;padding:6px !important;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;}div.bsClear{clear:both;height:0;line-height:0;font-size:0;overflow:hidden;}div.bsPopupAwd{background:url(http://static.bshare.cn/frame/images//bshare_box_sprite2.gif) no-repeat top left;background-position:0 -624px;width:18px;padding-left:3px;text-align:center;float:left;margin-left: 2px;height:15px;font-size:12px;color:#fff;overflow:hidden;}div.bsRlogo .bsPopupAwd,div.bsRlogoSel .bsPopupAwd{float:left;margin:5px 0 0 -14px;}

    学习Javascript闭包(Closure)

    bShare.addEntry({ title: document.getElementById("page-title").innerHTML,url:window.location.href});

    作者: 阮一峰

    日期: 2009年8月30日

    包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

    下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

    一、变量的作用域

    要理解闭包,首先必须理解Javascript特殊的变量作用域。

    变量的作用域无非就是两种:全局变量和局部变量。

    Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

    var n=999;

    function f1(){    alert(n);  }

    f1(); // 999

    另一方面,在函数外部自然无法读取函数内的局部变量。

    function f1(){    var n=999;  }

    alert(n); // error

    这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

    function f1(){    n=999;  }

    f1();

    alert(n); // 999

    二、如何从外部读取局部变量?

    出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

    那就是在函数的内部,再定义一个函数。

    function f1(){

    var n=999;

    function f2(){      alert(n); // 999    }

    }

    在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

    既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

    function f1(){

    var n=999;

    function f2(){      alert(n);    }

    return f2;

    }

    var result=f1();

    result(); // 999

    三、闭包的概念

    上一节代码中的f2函数,就是闭包。

    各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

    由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

    所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

    四、闭包的用途

    闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

    怎么来理解这句话呢?请看下面的代码。

    function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){      alert(n);    }

    return f2;

    }

    var result=f1();

    result(); // 999

    nAdd();

    result(); // 1000

    在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

    为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

    这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

    五、使用闭包的注意点

    1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    六、思考题

    如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

    代码片段一。

    var name = "The Window";

    var object = {    name : "My Object",

    getNameFunc : function(){      return function(){        return this.name;      };

    }

    };

    alert(object.getNameFunc()());

    代码片段二。

    var name = "The Window";

    var object = {    name : "My Object",

    getNameFunc : function(){      var that = this;      return function(){        return that.name;      };

    }

    };

    alert(object.getNameFunc()());

    展开全文
  • javascript闭包获取table中tr的索引

    千次阅读 2015-05-04 15:10:31
    javascript闭包获取table中tr的索引<!DOCTYPE ...

    使用javascript闭包获取table标签中tr的索引

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
        <title>Document</title>
        <script type="text/javascript">
    $(function() {
        var $tabObj;
        $tabObj = $('table').find('tr');
        for (var i = 0, l = $tabObj.length; i < l; i++) {
            (function(i) {
                $tabObj.eq(i).bind('click', function(){
                    alert($tabObj.eq(i).attr('class'));
                    alert(i);
                })
            })(i);
        };
    })
    </script>
    
    </head>
    
    <body>
        <table>
            <tr class="item1"><td>11111</td></tr>
            <tr class="item2"><td>22222</td></tr>
            <tr class="item3"><td>33333</td></tr>
            <tr class="item4"><td>44444</td></tr>
            <tr class="item5"><td>55555</td></tr>
            <tr class="item6"><td>66666</td></tr>
        </table>
    </body>
    
    </html>
    
    展开全文
  • 一、闭包求法 、 二、求闭包示例 ( 关系图角度 ) 、 三、求闭包示例 ( 关系矩阵角度 ) 、 四、闭包运算与关系性质 、 五、闭包复合运算 、
  • 本文属于「算法学习」系列文章之一。... 各大OJ题目应用 题目链接 题解文章 POJ 1975 Median Weight Bead POJ 1975 Median Weight Bead【传递闭包】 POJ 3660 Cow Contest POJ 3660 Cow Contest【传递闭包
  • 闭包

    千次阅读 2016-03-05 11:26:16
    闭包  编辑 闭包是指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于以下两者的...
  • 二元关系的闭包是离散数学的重要内容,针对二元关系的性质,闭包分为自反闭包、对称闭包、传递闭包
  • js闭包深度讲解

    2021-01-12 22:59:06
    js的闭包是学习js过程中的重点,但是不得不说也是一个难点呀,其涉及到了js中的很多概念。我在学习js中也遇到了很多问题,这篇文章算是一个对闭包的总结,文章主要内容为闭包的基本知识点与对其理解上的一些难点的...
  • 相对来说python对字符串的处理是比较高效的,方法也有很多。其中maketrans和translate两个方法被应用的很多,本文就针对这两个方法的用法做一总结整理。 首先让我们先回顾下这两个方法: ① s.translate(table,str) ...
  • 离散数学-传递闭包的代码计算

    千次阅读 2021-04-28 22:11:19
    文章目录简单解释一下传递闭包例题手算代码实现完整代码与运行结果展示代码讲解第一步-获得关系矩阵第二步-根据Warshell算法计算得到传递闭包 简单解释一下传递闭包 传递闭包、即在数学中,在集合X上的二元关系R的...
  • JavaScript:闭包

    千次阅读 2016-06-02 16:31:10
    DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ; charset=utf-8" /> <script language="javascript" src="jquery.js"></script> $...
  • 关系的闭包运算 8.1 闭包的定义 8.2 闭包的求法 8.3 闭包运算的复合及性质 8. 关系的闭包运算 前面介绍了集合上二元关系的五种特性:自反性、反自反性、对称性、反对称性、传递性。对于一个集合上的二元关系,可以...
  • 闭包详解

    2017-05-16 10:23:41
    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。闭包的特性 闭包有三个特性:1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制...
  • 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。闭包的特性闭包有三个特性:1.函数嵌套函数2.函数内部可以引用外部的参数和变量3.参数和变量不会被垃圾回收机制回收闭包的...
  • 嵌套函数及闭包

    2020-12-21 07:27:50
    这篇文章其实是要讲闭包的一些初级应用,但是为了将闭包,我们还是从嵌套函数开始说吧,纵使所有的JavaScript函数都可以说是闭包,但是只有当一个嵌套函数被导出到它所定义的作用域之外时,这种闭包才是有趣的。...
  • C++中闭包的简单实现

    2020-07-10 15:03:42
    这个问题的起源是想把成员函数封装为回调函数,...如果函数带参数或者是成员函数,使用bind可以实现一个闭包的作用,将对象本身、参数都封装进来,返回一个function对象。例如: struct X { int foo(int data)
  • 一、求闭包: 例1:设有关系模式R( A, B, C, D, E), F={AB→C,B→D, C→E, EC→B, AC→B}。求( AB) +。 求解方法: 解: 第一次: X(0)=X=AB 搜索F中每一个函数依赖得到AB→C,B→D X(1)=AB∪C∪D=...
  • 闭包理解

    2017-01-05 15:03:31
    1.闭包可以简单理解为一个匿名内部类 2.理解闭包必须先理解作用域链 举例: Document var data=[]; for (var i = 0; i ; i++) { data[i]=function () { console.log(i) } } ...
  • JavaScript 闭包详解

    万次阅读 2016-09-09 21:14:52
    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 闭包的特性 闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制...
  • 闭包用法:经典案例

    千次阅读 2015-04-08 11:02:54
    闭包用法:经典案例 学习一样技能,最终是想把它投入运用。我们从JS函数的最基础用法,一直研究到作用域链、闭包,这个过程消耗了我们大量的心血,那么闭包到底能用在哪些场景里面呢?下面将使用逐个枚举的方式给出...
  • 学习闭包

    2017-04-20 21:29:00
    何为闭包闭包是指 有权访问 另一个函数作用域 中的变量 的函数,常见的创建方式是 在一个函数的内部创建另一个函数 ,通过另一个函数访问这个函数的局部变量。 闭包的特性 闭包有三个特性: 函数嵌套函数 函数...
  • 离散数学,Js 中闭包的解释和联系

    千次阅读 2018-11-14 15:12:43
    总共分三部分说明闭包问题:   (1)部分 转发自: https://blog.csdn.net/wzwdcld/article/details/44783459,如侵权,请告知删除。 二元关系  设S是一个非空集合,R是关于S的元素的一个条件.如果对S中任意一...
  • 创建一个js文件,名为testClosure.js: ? 1 2 3 4 5 6 7 8 9 (function () { function a() { alert('i am a');... outFunc = function () {...
  • js闭包剖析

    2016-07-16 11:00:02
    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收 闭包是指...
  • JavaScript闭包及实现循环绑定事件

    千次阅读 2014-12-14 23:53:48
    DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 闭包 第1条记录 第2条记录 第3条记录 第4条记录 第5条记录 第6条...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,527
精华内容 1,810
关键字:

tr闭包