闭包

作者: yuanjiex | 来源:发表于2018-08-28 08:43 被阅读0次

1、变量作用域

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

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

javascript语言的特别之处就在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。

注意点:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明的是一个全局变量!

function foo(){

    varx = 1;

    returnfunction (){

        alert(++x);//2    }

}varbar = foo();

bar();

先问一个问题,这里到底谁是闭包?是foo还是那个匿名函数?

闭包的产生原理

在JavaScript中,函数可以用来分隔作用域,当foo执行(activation)的时候,产生了一个foo的动态作用域,然后这个动态作用域把变量x和那个return的匿名函数装(push到栈)了进去,一般情况下,当函数执行完毕时,它会自动销毁(pop出栈)内部产生的变量和函数,跳出这个作用域环境,返回到上一层(context)。但是在这里,由于foo作用域内部的变量和函数与它作用域外部的变量bar存在暧昧关系(bar引用了foo()的返回值),所以变量x和匿名函数没法从foo作用域中被销毁,于是也就产生了我们平时所说的闭包。刚才说的push到栈和pop出栈很已经显然不适用于闭包,这和栈的结构是相悖的,那么闭包是怎样的内存分配方式呢?这个我们后面再说。闭包既不是foo函数,也不是那个匿名函数,而是变量x、匿名函数、上下文环境三者一起同时存在的结果。

闭包存在有这么两个条件

没有被创建它的上下文销毁

引用了自由变量(没有在函数块中定义,也没有从arguments中送入,如上匿名函数中的变量x,就是一个自由变量)

  说了这么多,再看看下面这个例子:

varx = 1;function foo(){

    alert(x);

}

~function(){

    varx = 2;

    foo(); //1

}();

你可能又不解了,这里怎么会弹出1呢?先说明下,下面三种写法效果是等价的(但解析方式并不一样,A、C是一类,B是另一类,这里就不多说了):

~function(){

    varx = 2;

    foo();   

}();//A

(function(){

    varx = 2;

    foo();   

}());//B

(function(){

    varx = 2;

    foo(); 

  })();//C

闭包的内存分配方式

  回归正题,上面为什么会弹出1,这个闭包的情况和上面所述的闭包有些不太相同,上面的闭包是因为作用域中的东西没有被销毁,并与上下文存在暧昧关系,而这里并不存在销毁什么的问题,但是它依旧是一个闭包。在foo中,x是一个自由变量,当foo这个闭包产生的时候,foo的上下文会被保存,而foo处于Activation状态的时候,它会先从他所处的Activation

Object(foo内部声明的变量、函数等非自由变量)中查找需要的对象,如果没有找到,便会从它开始保存的上下文中查找对象,如果还没找到,才会跑到他的上一层作用域链中取那个值为2的x。

  再回到之前说的那个问题,闭包的内存分配方式。很明显,如果闭包的内存分配是利用栈的结构实现的,那进入foo运行状态的时候,应该会push一个“全局“的x,也就是向上找到那个var x =2,接着alert(2);但事实并非如此,上层作用域的闭包数据是动态分配的内存,也就是保存在堆里,解析器会记录这个闭包数据被引用的次数,当引用次数为0的时候,垃圾回收机制(GC)会自动处理这些垃圾。

闭包是如何霸占内存的

  IE经常会因为闭包的存在而导致内存居高不下。第一个例子中:

window<=>foo<=>匿名函数<=>bar<=>window

  形成了一个引用循环,即便是

bar = null;

  这个匿名函数的引用次数依旧大于0。需要注意的即便是是delete一个变量并不是删除这个变量的引用对象,而是断开这个引用,其作用就是让引用对象的引用次数减1. 这样一来,这个闭包就死在内存里了,于是它也就一直占用着内存= =

相关文章

  • swift-闭包

    闭包 闭包定义 闭包简化 - 尾随闭包 闭包参数 闭包返回值 闭包的循环引用

  • 闭包,闭包,闭包

    1、这家伙到底是什么? 网上关于这个的讨论的太多了太多了,有各种的举例子,但是大部分还在寻找这个答案的小伙伴对于变...

  • 闭包-Closures [swift 5.1]

    闭包的语法 尾随闭包 闭包逃离 自动闭包

  • Day7 闭包(Closures)

    本页包含内容:• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包 1、闭包表达式 闭包...

  • Python闭包

    闭包 = 环境变量 + 函数 调用闭包内部的环境变量 闭包的经典误区 闭包与非闭包实现人类走路 非闭包 闭包

  • 闭包(closure)

    ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...

  • swift- 闭包一

    /*• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包*/

  • (9) python之闭包

    闭包闭包 = 函数 + 环境变量(函数定义的时候) 一个最简单的闭包 闭包不受外部变量影响 非闭包 闭包 闭包 只...

  • Swift-进阶 :闭包(二)逃逸闭包 & 非逃逸闭包

    本文主要分析逃逸闭包 、非逃逸闭包、自动闭包 逃逸闭包 & 非逃逸闭包 逃逸闭包定义 当闭包作为一个实际参数传递给...

  • javascript闭包详解

    跟我念 bi 闭 bao包 ,闭包的闭,闭包的包。。 闭包的简介 在计算机科学中,闭包(英语:Closure),又...

网友评论

      本文标题:闭包

      本文链接:https://www.haomeiwen.com/subject/tmzxwftx.html