在学习javascript的过程中经常会看到别人谈论闭包,最近在网上到处查看资料终于算是明白一些了。
先看一个例子,在一个函数的内部,再定义一个函数。
比如:
function a()
{
function b()
{ var i=1;
return i;
}
}
内函数b只允许在函数a的内部调用,而不允许在函数a的外部调用。比如:
function a()
{
function b()
{ var i=1;
return i;
}
b(); //正确
}
b();错误
这就是函数作用域的问题。
为了解决这个问题,有两种办法。
第一是定义引用,如:
var c;
function a()
{
function b()
{ var i=1;
return i;
}
c=b;
}
a();
c();
第二种办法是在内函数外定义返回,如:
function a()
{
function b()
{ var i=1;
return i;
}
return b;
}
var c=a();
c();
创建闭包的常见方式就是在一个函数内部创建另一个函数,就是我们上面说的内部函数。闭包是指有权限访问另一个函数作用域的变量的函数。
我们在看下一个例子:
for (var i = 0; i < li.length; i++) {
li[i].onclick=function() {
alert(i);
}
}
有四个li标签,分别点击四个li标签后,会打印什么数字,这是一道网易笔试的选择题,我当时毫不犹豫的选择了0,1,2,3 上面讨论了闭包的问题,想调用内部函数必须通过两种方法之一,这里是通过引用的方式调用。可以理解为:
for (var i = 0; i < li.length; i++) {
function b() {
alert(i);
}
li[i]=b;
}
for (var j=0;j<li.length;j++)
li[j]();
当执行内部函数b时,外函数的循环已经执行完毕,i已经变成了4,外函数执行完毕后i被闭包所引用,所以外函数在内存中保留了i的值为4(这里的意思是,i的作用域是整个外函数包括内函数,由于内函数可能会用到i,所以外函数会保留i的值直到函数被销毁或者清理内存)。内函数通过引用调用,会打印4。
此时,为了能够实现打印0,1,2,3 我们的匿名函数就出来了。
代码改为如下所示:
for (var i = 0; i < spans.length; i++) {
( function(num) {spans[i].onclick=function() {
alert(num);
}})(i);
}
一个立即执行的函数又创建了一层闭包,函数声明放在括号内就变成了表达式,后面再加上括号就是调用,i当参数传入,函数立即执行,num保存每次i的值。有时候我们也会见着末尾是()没有i的,那是因为不用传参数,直接是(function(){})();的写法。