“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。在PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。
函数作用域外调用函数作用域内变量的函数称为闭包。也就是其中一个函数是闭包。
严格意义上来讲,任意函数都可以称作为闭包。
1 function B(){ 2 var i=0; 3 return function(){ 4 alert(i++); 5 } 6 } 7 8 var A=B(); 9 10 //注意B();的返回值A(); 11 12 //0A(); 13 14 //1A是B函数作用外访问B函数作用内变量 i 的函数;
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就会被回收。(关于Javascript的垃圾回收机制将在后面详细介绍)
B运行完毕后,等待javascript垃圾回收就如同B运行完,系统回收了笼子,小狗是不是可以被释放了。但此时系统发现A是一颗大树,穿过笼子拴住了小狗,系统无法顺利回收笼子,小狗也被大树拴住了,笼子不能被回收,小狗也不能被释放。要想回收笼子,释放小狗就必须得先把大树毁掉,或者解除绳索关联。
1 function fun(n,o) { 2 console.log(o) 3 return { 4 fun:function(m){ 5 return fun(m,n); 6 } 7 }; 8 } 9 var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? 10 var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? 11 var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,? 12 //问:三行a,b,c的输出分别是什么?
1.使用闭包代替全局变量
2.函数外或在其他函数中访问某一函数内部的参数
3.在函数执行之前为要执行的函数提供具体参数
4.在函数执行之前为函数提供只有在函数执行或引用时才能知道的具体参数
5.为节点循环绑定click事件,在事件函数中使用当次循环的值或节点,而不是最后一次循环的值或节点
6.暂停执行
7.包装相关功能
1 function f1(){ 2 var test=111; 3 tmp_test=function(){return test;} //tmp_test是全局变量,这里对test的引用,产生闭包 4 } 5 function f2(){ 6 alert("测试一:"+tmp_test()); 7 var test1=tmp_test(); 8 alert("测试二:"+test1); 9 } 10 f1();//测试一:111 11 f2();//测试二:111 12 alert(tmp_test()); //111 13 tmp_test=null;
某些情况下,是无法为要执行的函数提供参数,只能在函数执行之前,提前提供参数。
有哪些情况是延迟执行?
如:
setTimeOut
setInterval
Ajax callbacks
event handler[el.onclick=func 、 el.attachEvent("onclick",func)]
1 //无法传参的情况 2 var parm=222; 3 function f1(){alert(111)} 4 function f2(obj){alert(obj)} 5 setTimeout(f1,500);//正确,无参数 6 var test1=f2(parm);//执行一次f2函数 7 setTimeout(f2,500);//undefined,传参失败 8 setTimeout(f2(parm),500);//参数无效,传参失败 9 setTimeout(function(parm){alert(parm)},500);//undefined,传参失败 10 document.getElementById("hello").onclick=f1;//正确 11 document.getElementById("hello").attachEvent("onclick",f1);//正确 12 //正确做法,使用闭包 13 function f3(obj){return function(){alert(obj)}} 14 var test2=f3(parm);//返回f3的内部函数的引用 15 setTimeout(test2,500);//正确,222 16 document.getElementById("hello").onclick=test2;//正确,222 17 document.getElementById("hello").attachEvent("onclick",test2);//正确,222