在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法 认为闭包是由函数和与其相关的引用环境组合而成的实体。
例1:
<html>
<body>
<script type="text/javascript">
function test(j) {
var i = 0;
return function() {
alert("i:"+i+" ,j:"+j);
alert(j + i++);
}
};
test(1)();//提示1
test(1)();//还是提示1
test(1)();//依然提示1
</script>
</body>
</html>
解释:test(1)();表示立即执行函数test(1)。
结果:依次弹出1,1,1
分析:每次i都被重置为0.
稍微改造一下:
例2:
<html>
<body>
<script type="text/javascript">
function test(j) {
var i = 0;
return function() {
alert("i:"+i+" ,j:"+j);
alert(j + i++);
}
};
var c = test(1);
c();//提示1
c();//提示2
c();//提示3
</script>
</body>
</html>
解释:c();表示立即执行test(1), 即test(1)().
结果:依次弹出1,2,3
分析:闭包是由函数和与其相关的引用环境组合而成的实体。以上js代码中,function test(j)及引用它的环境3个c()构成实体即是闭包。在闭包中变量(如此处的 i)全程共享,此处i相当于闭包中的全局变量,而不随每次c()运行而重置变量 i 为0,所以每次运行c()变量i都会累加,而每次传入的变量j不变为1。
比较分析:
例1与例2的区别:例2多了这句var c = test(1);并在后面引用,此时这个引用指向函数test();
而例1直接调用test(),例1这种用法比例2更常见,是我们平时用的最多的;
这里就用“闭包是由函数和与其相关的引用环境组合而成的实体”这句话来解释。例2中js代码中最后4行就是对test()的引用,构成函数test()的引用环境,与函数test()一起组成的实体为闭包。闭包中自由变量i与函数test()一同存在。
更深入理解js解析过程:
例1中,三次直接运行test(1)()会生成三次函数的调用,函数指针指向三个不同的函数调用,这三次生成属于三个独立的个体互补影响,每次函数test()都能重新完整运行,i都能初始化为0;
但是例2中,用var c引用test()后(此时 i 离开创造它的环境test()函数),只有一份函数指针指向同一个函数调用,所以后面的虽是三次c(),但还是运行的同一个函数,因为函数中的自由变量i早在加载的时候就已经赋值为0了,放在一个属于指向这个函数test()的“暂存区”,让每次调用都共享这个变量i的值(被引用的自由变量 i 与引用它的函数test()一同存在),允许所有指向同一个函数调用的之后每次调用修改 i 的值并且会生效。所以,指向同一个函数调用的三个c()都能修改 i 的值,并且修改都生效了。
这与wiki中的定义是吻合的。