首页 > 代码库 > 关于闭包

关于闭包

闭包:首先什么是闭包,让我们先来思考一下这个问题。
通过使用闭包我们先假定给闭包几个定义:
  1. 函数返回函数
  2. 一个函数访问另一个函数的变量行为
  3. 访问外部作用域变量的函数
  4. 子函数用父函数的变量
  5. ……
这也是在使用的时候我们的一些认识,当然这些定义正确不正确暂且不论,因为下面还会深入的剖析闭包。首先先明确一点,在各种语言当中都会有闭包这种形式的存在,只是JavaScript在所有语言当中算是学习难度比较低的语言,或者说是入门门槛比较低的语言,所以大家不用对闭包这个概念有什么恐惧,经过下面的剖析你一定会有一个深入的认识。
理解闭包首先我们先要了解作用域,那什么是作用域呢,在JavaScript中(在ES6之前)作用域是函数作用域,意思就是我们声明一个变量在当前函数当中可以访问的到,我们看下面的代码:
 1 function a(){ 2 var a=12; 3 } 4 a(); 5 function b() 6 { 7 var a=5; 8 } 9 b();10 alert(a) //Uncaught ReferenceError: a is not defined;

 

上面我们声明了两个函数,我们都知道a这个变量是在外层是访问不到的,就想上面再外面访问就会报a is not defined这样一个错误,然后我们在看下面一段代码:
function c(){
alert(a);
}
c();//Uncaught ReferenceError: a is not defined;
我们把之前的代码和这段代码结合起来运行,同样也会报a is not defined这样一个错误;
我们再看一段代码:
1 function foo(){2 var a = 12;3 function show(){4 alert(a);5 }6 show();7 }8 foo();//12;

 

结果是12,可以访问的到;
我们再看下面一段代码:
1 function foo(){2      alert(a); 3     function show(){4      var a = 12; 5     } 6     show(); 7 } 8 foo();//Uncaught ReferenceError: a is not defined;

 

这里的a是访问不到的,所以抛出了a is not defined;这样一个错误,这样我们就对作用域有了一个认识,所以我们得到了下面的结论:
  1. 每个函数都有自己的作用域;
  2. 函数绝对不能访问别人的作用域——例外:函数的父函数;
  3. 子函数可以访问父函数的作用域;父级没法访问子级;
我们对于作用域有了认识,下面我们来讨论另外一个问题:生命周期;
首先我们需要认识到计算机的资源是有限的,我们买回来的电脑手机或者其他智能设备比如说RAM:2GB,面对这样的问题就会产生一个新的问题,因为我们声明的变量会存储在内存里,这个变量不能永远存在于内存当中,所以就产生了一个机制,叫垃圾回收(GC)。作为浏览器会智能的帮我们去处理,当然处理的方式会需要有一个规则,就是什么样的会被回收,什么样的又不会被回收呢?
作为现实生活中我们对待东西的态度是有用的保留,没有用的会被丢弃,在浏览器中也是这样的机制,我们看下面一段代码:
var a=‘youdao‘;
a=null;
当a=null的时候,‘youdao‘这一段字符串就会从内存中被回收;
那怎样就不会被回收呢?看下面的代码:
a=xxx;
b=xxx;
 
a=null;
b=null;
首先浏览器在保存变量的时候相同的东西只会保存一份,只是把变量去等于了一个地址,而内存中只有xxx,通过上面的原理我们知道了当a,b都等于xxx时,xxx只保存了一份,当a=null的时候内存中的xxx并没有被回收,因为b也在引用这个地址,而只有在b=null的时候,xxx这份数据才会被回收;
当然讲了这么多,这个跟作用域是有联系的,看下面代码:
var a=‘12‘; function show(){ alert(a); } show();
而当函数内去访问外部变量时,也会成为一个引用;
再看下面的代码:
function show(){
var a=12;
alert(a);
}
 
//执行show之前,a不存在
show(); //执行show当中,a创造出来了
//执行show之后,a、show都会消失
通过上面的例子可以看到我们定义的函数变量等等只是定义了没有去使用是会一直存在于内存,使用后会被回收,而函数定义的如果函数不执行,也是不存在的。
看一下下面的例子:
例子1:
var a;
 
window.onload=function (){
var arr=[1,2,3];
a=arr;
};
例子2:
window.onload=function (){
var arr=[1,2,3];
 
function show(){
arr;
}
 
oBtn.onclick=show;
};
我们思考一下,两个arr的生存周期。
先看第一个例子:
函数外定义了一个a 函数内定义了一个 arr,然后a =arr ,这里就形成了互相引用,此时的arr就永远不会被回收;
第二个例子:
函数外定义了一个arr 在show里进行了引用,当oBtn.onclick的时候,arr被使用了,所以arr就会被回收。
 
通过上面的分析,就可以得到下面的结论:
闭包:
1.子函数能访问父函数的东西
2.*子函数能延长父函数局部变量的生存时间
3.产生一个独立的空间

关于闭包