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

  

时间: 2024-11-05 06:08:55

js学习笔记之作用域链和闭包的相关文章

JS详细图解作用域链与闭包

JS详细图解作用域链与闭包 攻克闭包难题 初学JavaScript的时候,我在学习闭包上,走了很多弯路.而这次重新回过头来对基础知识进行梳理,要讲清楚闭包,也是一个非常大的挑战. 闭包有多重要?如果你是初入前端的朋友,我没有办法直观的告诉你闭包在实际开发中的无处不在,但是我可以告诉你,前端面试,必问闭包.面试官们常常用对闭包的了解程度来判定面试者的基础水平,保守估计,10个前端面试者,至少5个都死在闭包上. 可是为什么,闭包如此重要,还是有那么多人没有搞清楚呢?是因为大家不愿意学习吗?还真不是,

JS 之作用域链和闭包

1.JS无块级作用域 <script> function Main(){ if (1==1){ var name = "alex"; } console.log(name); } Main(); </script>执行结果:{}即块级作用域. alex 2.JS采用函数作为作用域链 <script> function Main(){ var innerValue = "alex"; } Main(); console.log(in

sizzle.js学习笔记利用闭包模拟实现数据结构:字典(Map)

sizzle.js学习笔记利用闭包模拟实现数据结构:字典(Map) 这几天学习和查看了jQuery和Property这两个很流行的前端库的御用选择器组件Sizzle.js的源代码,收获还是相对多的!之前一直做使用Java语言开发,其丰富的组件类库使得开发效率那叫一个快呀!突然转来做JavaScript一时间还有点儿不适应(快半年了),不过自从看见那么多漂亮的网站和对JavaScript接触的越来越多,也发现了其中的一些乐趣.正如自己一直坚信的那样,编程语言仅仅是工具,重要的是编程思想!使用Jav

1--面试总结-js深入理解,对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This

参考一手资料:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/中文翻译版本:https://zhuanlan.zhihu.com/p/32042645 Javascript 是一种单线程编程语言,这意味着它只有一个调用栈,call Stack(调用栈 ,,先入后出) 核心:对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This js原型链? 定义 原型对象也是简单的对象并且可以拥有它们自

js内存空间 执行上下文 变量对象详解 作用域链与闭包 全方位解读this

内存空间:https://blog.csdn.net/pingfan592/article/details/55189622 执行上下文:https://blog.csdn.net/pingfan592/article/details/55189804 变量对象详解:https://blog.csdn.net/pingfan592/article/details/56009330 作用域链与闭包:https://blog.csdn.net/pingfan592/article/details/5

JS学习笔记-OO疑问之封装

封装是面向对象的基础,今天所要学习的匿名函数与闭包就是为了实现JS的面向对象封装.封装实现.封装变量,提高数据.系统安全性,封装正是面向对象的基础. 匿名函数 即没有名字的函数,其创建方式为 function(){...} 单独存在的匿名函数,无法运行,可通过赋值给变量调用或通过表达式自我执行来实现运行. 1.赋值给变量为一般的函数使用方式 var run = function(){ return '方法运行中'; }; alert(run()); 2.通过表达式自我执行 (function(a

在chrome开发者工具中观察函数调用栈、作用域链与闭包

在chrome开发者工具中观察函数调用栈.作用域链与闭包 在chrome的开发者工具中,通过断点调试,我们能够非常方便的一步一步的观察JavaScript的执行过程,直观感知函数调用栈,作用域链,变量对象,闭包,this等关键信息的变化.因此,断点调试对于快速定位代码错误,快速了解代码的执行过程有着非常重要的作用,这也是我们前端开发者必不可少的一个高级技能. 当然如果你对JavaScript的这些基础概念[执行上下文,变量对象,闭包,this等]了解还不够的话,想要透彻掌握断点调试可能会有一些困

Angular JS 学习笔记

特定领域语言 编译器:遍历DOM来查找和它相关的属性, 分为编译和链接两个阶段, 指令:当关联的HTML结构进入编译阶段时应该执行的操作,可以写在名称里,属性里,css类名里:本质上是函数 稳定的DOM:绑定了数据模型的DOM元素的实例不会在绑定的生命周期发生改变 作用域:用来检测模型的改变和为表达式提供执行上下文的 AngularJS 和其它模板系统不同,它使用的是DOM而不是字符串 指令: 由某个属性.元素名称.css类名出现而导致的行为,或者说是DOM的变化 Filter过滤器:扮演着数据

(第四天)作用域链、闭包

前言 JavaScript是基于词法作用域的语言:通过阅读包含变量定义在内的数行源码就能知道变量的作用域.全局变量在程序中始终都是有定义的.局部变量在声明它的函数体内以及其所嵌套的函数内始终是有定义的. 如果将一个局部变量看做是自定义实现的对象的属性的话,那么可以换个角度来解读变量作用域.每一段JavaScript代码(全局代码或函数)都有一个与之关联的作用域链(scope chain).这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量.当JavaScript需要查找