浅谈闭包
想弄清闭包,我们首先得知道我们为啥要用到闭包呢,我们想要在一个函数内部取到函数外部的变量,或者调用函数外部的方法都是很容易的,因为javascript查找变量或方法都是逆着作用域链向上查找的,但是我们现在有了这样一个需求:我们想在函数外面取到函数内部一个临时变量的值,这样的需求使得我们违背了javascript的基本原则。而闭包恰好帮助我们解决了这个问题。
接下来我们看一个例子:
function setName(){
var name="CSDN";
function getName(){
return name;
}
}
getName函数是不是取到了setName函数内部的临时变量,这确实是的。
我们再看一个经典的错误例子:
我们想在数组的每项上绑定一个函数,希望他执行的时候能一次打印0,1,2,,,9;
但是发现,他只能打印10个10!
function consoles(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=function(){
console.log(i);
}
}
return arr;
}
var arr=consoles();
for(var j=0;j<10;j++){
arr[j]();
}
我们稍微把代码改一下:
function consoles(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=(function(num){
return function(){
console.log(num);}
})(i)
}
return arr;
}
var arr=consoles();
for(var j=0;j<10;j++){
arr[j]();
}
我们使得一个匿名函数自执行,返回一个函数给数组各项,这样就行了。
弄懂这两个基本可以理解闭包了,在讲这两个例子之前咋们还得说一个例子做一个铺垫~~(不要嫌我啰嗦啦。。。)
function setName(){
var name="CSDN";
function getName(){
return name;
}
}
这就是文章开头写的那个例子,如果我们直接在setName外面调用getName肯定是得不到name值的,但是如果我们这样稍稍变化一下呢,
function setName(){
var name="CSDN";
return function (){
alert(name);
}
}
var get=setName();
get();
我们在setName内部返回一个函数,在函数外部用get变量接受,继续调用get函数,打印CSDN,这样为什么就行了呢?原因就是我们返回的函数可能会被再次调用,所以他用到的setName的局部变量不会在setName调用完毕之后就被gc回收,局部变量name会常驻内存,当我们再次调用get函数即setName返回的函数,就会弹出”CSDN”;
我们这时候再回头看一下那个经典例子:
function consoles(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=function(){
console.log(i);
}
}
return arr;
}
为什么我们循环执for(j=0;j<10;j++){
arr[j]();
}
会打印10 个10 呢?
我们在这个函数中返回的是一个数组,每个项都存着一个函数,这跟我们之前直接返回一个函数,再调用,是不是大同小异啊,我们返回的数组中的10个函数有可能会被再次调用,所以我们在consoles函数中定义的局部变量i,是不会在consoles执行完毕就被垃圾回收机制回收,在循环结束i的值为10,这个值会一直保存在内存中,当arr[j]()调用时就会寻找到这个i值,这样就会打印10个10,如果我们在内部循环结束重新给i赋值1,这样就会打印10 个1了,现在清楚点了吧~~
那为什么我们这样改一下就行了呢?
function consoles(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=(function(num){
return function(){
console.log(num);}
})(i)
}
return arr;
}
var arr=consoles();
for(var j=0;j<10;j++){
arr[j]();
}
我们使用匿名函数的自执行,把i值传入匿名函数内部,我们返回的是表达式!这个表达式当然能够接收到我们传入的i值即num;
闭包就是能够访问函数内部变量的函数,闭包有两个特点1、他能够访问函数内部的变量2、她能让函数内部的变量常驻内存
正是由于这样我们才可以访问函数的局部变量,当闭包执行的时候,包含他的函数的执行环境会加入到闭包的执行环境中去,这个才是关键。。。。闭包越多消耗的内存就越多,因为她要保存包围他的函数的执行环境,所以不用闭包就要手动释放,通知垃圾回收机制回收内存,以免造成内存泄露。
真正要搞明白闭包,还是要清楚作用域链和函数的执行环境~~打好基础很重要~这样理解起来就会轻松一点了~~