实例2
这个例子和上个例子结果是一样的,但是有一点不同,函数f并不返回一个函数,而是新建一个全局变量n,代码如下
var n;
function f(){
var b = "b";
n=function(){
return b;
}
}
所以可以直接n()来访问函数f里的变量b
通过上面两个例子我们就可以说当一个函数指向了它的父作用域,其作用是指向局部变量,就可以称之为闭包。
闭包其实就提供了一个借口,一个让外部访问内部的变量的方法
当我们创建了个传递参数的函数f,这个参数就变成了函数f的局部变量了。我们可以创建一个f的内部函数来返回这个参数
function f(arg){
var n =function(){
return args;
}
arg++;
return n;
}
var m= f(123);
m();//124
闭包在循环中的应用
再循环中很容易引起一些bug,虽然表面是正常的。
看如下的代码
function f(){
var a = [];
var i;
for(i=0;i<3;i++){
a[i] = function(){
alert(i);
return i;
}
}
return a;
}
var a= f();
a[0]();//3
a[1]();//3
a[2]();//3
新建个循环,我们的目的是每次循环都新建一个函数,函数返回的是循环的序列值也就是i。我们看看以上代码的运行结果
都是为3.而我们期望的结果是1,2,3。
到底是为什么呢?我们新建了三个闭包,都指向了变量i。闭包并没有记住变量i的值,它仅是变量i的引用。在循环结束后,i的值是3,所以结果都是3了。
来看看正确的写法
function f() {
var a = [];
var i;
for(i = 0; i < 3; i++) {
a[i] = (function(x){
return function(){
alert(x);
return x;
}
})(i);
}
return a;
}
var a = f();
a[0]();//0
a[1]();//1
a[2]();//2
我们又用了一个闭包,把变量i变成了局部变量x了,x变量每次都是不同的值了。如果没有彻底理解自调用函数那就如下写法就可以明白了
function f() {
function makeClosure(x) {
return function(){
return x;
}
}
var a = [];
var i;
for(i = 0; i < 3; i++) {
a[i] = makeClosure(i); //makeClosure,用来记忆i的值。
}
return a;
}