闭包的定义:有权访问另一个函数作用域内变量的函数都是闭包。
闭包出现的原因:因为js的每一个函数都是独立的(封装性),它可以获取外界信息,但是外界却无法直接看到里面的内容。为了让函数内部的变量被另一个函数所使用,所以出现了闭包。
闭包的本质:闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!
举例:
//inc函数访问了fun1函数内的变量n
function fun1(){
var n=0;
function inc(){
n++;
console.log(n);
}
inc();
inc();
}
fun1();
//输出
[Web浏览器] "1"
[Web浏览器] "2"
function fun2(){
var n=0;
this.m=1;
this.inc=function(){
n++;
console.log(n);
}
}
var f=new fun2();
console.log("n="+f.n);
console.log("m="+f.m);
f.inc();
f.inc();
//输出
[Web浏览器] "n=undefined"
[Web浏览器] "m=1"
[Web浏览器] "1"
[Web浏览器] "2"
function fun3(){
var n=0;
this.inc=function(){
n++;
console.log(n);
}
return inc; //没有(),注意,函数名只是一个标识(指向函数的指针),而()才是执行函数
}
var f=fun3();
f(); //在此时才执行了inc()
f();
//输出
[Web浏览器] "1"
[Web浏览器] "2"
以下例子理解函数的执行与否:
//该例子不是闭包
function fun4(){
var n=0;
this.inc=function(){
n++;
console.log(n);
}
return inc(); //有(),则在return的时候就执行了一次函数
}
var f=fun4;
f();
f();
//输出
[Web浏览器] "1"
[Web浏览器] "1"
function fun5(){
var m=2;
return m;
}
var f=fun5();
console.log(f);
console.log(f());
//输出
[Web浏览器] "2"
[Web浏览器] "Uncaught TypeError: number is not a function"
function fun6(){
var m=2;
return m;
}
var f=fun6;
console.log(f);
console.log(f());
//输出
[Web浏览器] "fun6的定义和函数体"
[Web浏览器] "2"
单纯的一句 var f = function() { alert('Hi'); }; 是不会弹窗的,后面接一句 f(); 才会执行函数内部的代码。
是不是以为自己看懂了?那我们来看看下面这个
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
console.log(funcs[i]());
}
//输出
10个10
和我想象的答案不一样啊。一首凉凉,是哪里出了问题呢,其实只需多一行代码即可看懂
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
console.log(i); //执行createFunctions()时执行了
result[i] = function(){
console.log("i="+i); //执行createFunctions()的时候没有执行这个
return i;
};
}
console.log("end_i="+i); //createFunctions()执行完毕,i=10
return result;
}
var funcs = createFunctions(); //执行createFunctions(),并且将funcs指向了result
console.log(funcs); //看看这时候的funcs是什么吧!
for (var i=0; i < funcs.length; i++){
console.log(i+"--"+funcs[i]());
}
//输出
[Web浏览器] "0"
[Web浏览器] "1"
[Web浏览器] "2"
[Web浏览器] "3"
[Web浏览器] "4"
[Web浏览器] "5"
[Web浏览器] "6"
[Web浏览器] "7"
[Web浏览器] "8"
[Web浏览器] "9"
[Web浏览器] "end_i=10"
[Web浏览器] "function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
},function (){
console.log("i="+i);
return i;
}"
[Web浏览器] "i=10"
[Web浏览器] "0--10"
[Web浏览器] "i=10"
[Web浏览器] "1--10"
[Web浏览器] "i=10"
[Web浏览器] "2--10"
[Web浏览器] "i=10"
[Web浏览器] "3--10"
[Web浏览器] "i=10"
[Web浏览器] "4--10"
[Web浏览器] "i=10"
[Web浏览器] "5--10"
[Web浏览器] "i=10"
[Web浏览器] "6--10"
[Web浏览器] "i=10"
[Web浏览器] "7--10"
[Web浏览器] "i=10"
[Web浏览器] "8--10"
[Web浏览器] "i=10"
[Web浏览器] "9--10"
上面的代码翻译一下就是
var result = new Array(), i;
result[0] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
result[1] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
...
result[9] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
i = 10;
funcs = result;
result = null; // 此时result被自动回收了,i还被引用着,所以没有回收
console.log(i); // funcs[0]()就是执行 return i 语句,就是返回10
console.log(i); // funcs[1]()就是执行 return i 语句,就是返回10
...
console.log(i); // funcs[9]()就是执行 return i 语句,就是返回10