js学习笔记之作用域链和闭包
在学习闭包之前我们很有必要先了解什么是作用域链
一、作用域链
作用域链是保证对执行环境有权访问的所有变量和函数的有序访问。
这句话其实还是蛮抽象的,但是通过下面一个例子,我们就能清楚的了解到作用域链了。
1 var color="blue";
2 function changeColor(){
3 var anotherColor="red";
4 function swapColors(){
5 var tempColor=anotherColor;
6 anotherColor=color;
7 color=tempColor;
8 //这里面可以访问color、anotherColor和tempColor
9 }
10 //这里面可以访问anotherColor和color
11 }
12 //这里面只能访问color
以上代码涉及了3个执行环境:全局环境、changeColor()局部环境和swapColor()局部环境。在一个变量环境中只能访问他自己的环境和父执行环境。swapColor()的父执行环境就是changeColor(),而changeColor()的父执行环境就是全局环境。如果还不清楚可以参考下图
在f2()函数的局部环境中能访问自己和比它等级高的,也就是a,b,c,同理f1()函数环境访问b,a,全局环境只能访问c。
我们这时候会发现函数外部是无法访问内部的局部环境的,但是我们想突破作用域链怎么办呢?这时候就有了闭包共享作用域。闭包这个名词就出现了。
二、闭包
闭包在红宝书中的解释就是:有权访问另一个函数作用域中的变量的函数。
下来举一个简单的例子
1 function f1(){
2 var a=1;
3 return function(){
4 return a;
5 }
6 }
7 alert(a); /*结果为 a is undefined*/
8 var task=f1(); /*task就是闭包,有权访问其他函数作用域变量*/
9 alert(task());/*结果为1*/
下来我们再举一个闭包的例子
1 function f1(){
2 var n=0;
3 task=function(){ //匿名函数
4 n+=1;
5 }
6 //这部分为闭包
7 function f2(){
8 alert(n);
9 }
10 return f2 //返回
12 }
13 var text=f1();
14 alert(text());
15 task();
16 alert(text()); //结果依次为 0,undefined,1,undefined
text是f2闭包函数,实际上f2()被赋予一个全局变量,f2()始终在内存中,f1()是它的父级函数,所以f1()也始终在内存中,不会被销毁。执行一次task()后,值变为2。至于为什么会出现undefined是因为,undefined是text的返回值,也就是闭包函数无返回值了。
有时候我们想改变其他函数作用域里的变量,这时候就可以用闭包去解决。设置两个额外的函数去访问内部函数。
1 var setvalue,getvalue;
2 (function(){
3 var n=0;
4 getvalue=function(){
5 return n
6 }
7 setvalue=function(x){
8 n=x;
9 }
10 })(); //直接调用
11 alert(getvalue()); //结果为0
12 setvalue(456);
13 alert(getvalue());/*结果为456*/
这时候我们发现在外部就可以去改变内部变量值。
下来再举一个利用闭包循环遍历得到数组的值。有两个程序,可以对比一下两个程序的区别
例1:
1 function f1(){
2 var a=[];
3 var i=0;
4 for(i=0;i<3;i++){
5 a[i]=function(){
6 return i;
7 }
8 }
9 return a;
10 }
11 var text=f1();
12 alert(text[0]());
13 alert(text[1]());
14 alert(text[2]()); //结果都为3
因为闭包都指向局部变量i,只是给出了指针链接,对变量的引用,并没有对值作出改变。所以结果都为3
例2:
1 function f1(){
2 function f2(x){ //闭包
3 return function(){
4 return x;
5 }
6 }
7 var a=[];
8 var i=0;
9 for(i=0;i<3;i++){
10 a[i]=f2(i);
11 }
12 return a;
13 }
14 var text=f1();
15 alert(text[0]()); //结果为1
16 alert(text[1]());//结果为2
17 alert(text[2]());//结果为3
利用一个函数参数,用闭包去获取内部变量的值。
程序是这样走的:先判断谁进来--》调用闭包--》闭包返回内部函数参数--》最后再创建数组。
三、闭包的缺点
这上面几个例子确实体会到了闭包的强大,但是闭包也有明显的缺点,它使函数中的变量都保存在内存中,占用内存,导致页面加载缓慢。所以再退出函数前,将不用的局部变量删除。
四、总结
以上就是我学习闭包总结的一点小知识。大家互相交流哈 O(∩_∩)O。
附阮一峰老师对闭包的理解:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html?20120612141317#comments


浙公网安备 33010602011771号