JavaScript之闭包详解
2016-04-21 16:13
519 查看
前言:
闭包是Javascript语言的一个难点,也是它的特色,很多高级的应用都要依靠闭包来实现。之前看李炎恢老师虽然讲的特别的好,当时理解的并不是很深刻,今天通过实例来更好的解释什么是闭包,希望看后的朋友能够理解。
本篇文章分三部分来讲解闭包,首先说变量的作用域,然后说内部函数,和如何从外部读取局部变量,最后引入我们今天的主题——闭包。这篇文章用到的例子比较多,希望认真阅读,最后敲例子更能充分理解
在JavaScript中,变量的作用域分两种:全局变量和局部变量。
在Javascript中,在函数内部可以直接读取全局变量。
但反过来不行,在函数的外部无法读取函数内的局部变量
需要注意的是,函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上是声明了一个全局变量!
javascript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,javascript垃圾收集器才能释放内部函数的内存空间。也就是说,只要存在调用内部函数的可能,javascript就要保留被引用的函数。
看了上面的实例我想应该对闭包的组成有了一定的了解,那么我们来说一下闭包
(2)常驻内存;
实例:
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量(result),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
小结:
闭包就总结到这里,这次运用了大量的例子来说明闭包,希望阅读的朋友能够看懂。
闭包是Javascript语言的一个难点,也是它的特色,很多高级的应用都要依靠闭包来实现。之前看李炎恢老师虽然讲的特别的好,当时理解的并不是很深刻,今天通过实例来更好的解释什么是闭包,希望看后的朋友能够理解。
本篇文章分三部分来讲解闭包,首先说变量的作用域,然后说内部函数,和如何从外部读取局部变量,最后引入我们今天的主题——闭包。这篇文章用到的例子比较多,希望认真阅读,最后敲例子更能充分理解
一、变量的作用域
要理解闭包,首先必须理解Javascript特殊的变量作用域。在JavaScript中,变量的作用域分两种:全局变量和局部变量。
在Javascript中,在函数内部可以直接读取全局变量。
var n=123;//定义全局变量n function f1(){ alert("在函数内部访问全局变量n,n="+n);//在函数内部访问全局变量n }运行结果:
但反过来不行,在函数的外部无法读取函数内的局部变量
function f1(){ var n=123;//在f1函数内部定义局部变量n } alert("在函数外部访问局部变量n,n="+n); //在函数外部访问局部变量n,错误:n未定义
需要注意的是,函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上是声明了一个全局变量!
二、内部函数
首先来看一个实例:function A(){ function B(){ //B就是一个内部函数 alert("你好!"); } }由于函数B在函数A的内部,因此B函数在函数A内有效,但是在外部调用时无效的,如:
window.onload = B(); //外部调用无效 function A(){ alert("你好"); function B(){ //B就是一个内部函数 alert("你好!"); } } //报错误 B is not defined但是在内部调用是正确的
window.onload = A(); function A(){ function B(){ alert("你好!"); } B(); //内部调用A()是正确的 }
javascript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,javascript垃圾收集器才能释放内部函数的内存空间。也就是说,只要存在调用内部函数的可能,javascript就要保留被引用的函数。
三、如何从外部读取局部变量
在来看一个实例:function f1(){ var n=123;//f1函数内部的局部变量n //在f1函数内部定义一个f2函数 function f2(){ //在f2函数内部是可以访问局部变量n的 alert(n); // 123 } }在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,JavaScript中的函数名本身就是变量,所以函数也可以当作普通变量来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的返回值返回。
function f1(){ var n=123;//局部变量n //在f1函数内部声明的f2函数 function f2(){ alert(n); } return f2;//将f2函数作为f1函数的返回值 } var result=f1();//f1调用完后的返回值是一个f2函数,此时result就是f2函数 result(); // 123,调用f2函数
看了上面的实例我想应该对闭包的组成有了一定的了解,那么我们来说一下闭包
四、闭包的概念
在看视频中,闭包:是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量,由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。五、闭包的作用
(1)函数外部访问函数内部的函数或变量;(2)常驻内存;
实例:
function f1(){ var n=999; nAdd=function() { n += 1; } function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量(result),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
六、注意
由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存。过度使用闭包会导致性能下降,建议在分成有必要的时候才使用闭包。小结:
闭包就总结到这里,这次运用了大量的例子来说明闭包,希望阅读的朋友能够看懂。
相关文章推荐
- javascript-点击栏目条增加操作框
- js this对象
- javascript基础五 (cookie基础)
- js keyup、keypress和keydown事件 详解
- JS构造函数详解
- JS的prototype的共享机制分析
- JavaScript判断IE各版本最完美解决方案
- js中数组申请的区别
- 输出js对象的所有属性值
- JS原型链原理(链表)
- JS中的自定义属性
- JavaScript可否多线程? 深入理解JavaScript定时机制
- json解析入门(jsoncpp库)
- Eclipse去除js(JavaScript)验证错误
- JS图片预加载
- 深入理解javascript的闭包
- javascript数组
- 访问WEB-INF目录中的JSP文件
- JavaScript全局变量与局部变量重名的情况
- js ie中实现拖拽