JavaScript闭包研究
来源:互联网 发布:英美杂志软件 编辑:程序博客网 时间:2024/06/01 10:23
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka
摘要:本文主要讲了JavaScript闭包的原理、特点并用一些实例做了证明
一、闭包的概念与好处
1.1、什么是闭包?
闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包的特点:
1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
闭包:是指有权访问另外一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另外一个函数
1.2、javascript的垃圾回收原理
1.在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收;
2.如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
1.3、使用闭包的好处
那么使用闭包有什么好处呢?使用闭包的好处是:
1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
二、实例讲解
内部函数
让我们从一些基础的知识谈起,首先了解一下内部函数。内部函数就是定义在另一个函数中的函数。例如:
function outerFn () { functioninnerFn () {}}innerFn就是一个被包在outerFn作用域中的内部函数。这意味着,在outerFn内部调用innerFn是有效的,而在outerFn外部调用innerFn则是无效的。
当function里嵌套function时,内部的function可以访问外部function里的变量。
如下:
<!DOCTYPE html><meta charset="utf-8" /> <html><head></head><body> <button onclick="fun()">请点击这里</button> <script> function fun() { outfun(1); } function outfun(x) { var tmp = 1; function infun(y) { alert(x + y + (++tmp)); } infun(10); } </script></body></html>
输出结果;
不管执行多少次,都会alert 13,因为infun能访问outfun的参数x,也能访问outfun的变量tmp。但,这还不是闭包。当你return的是内部function时,就是一个闭包。内部function会close-over外部function的变量直到内部function结束。
将函数更改成如下就是闭包了:
<!DOCTYPE html><meta charset="utf-8" /> <html><head></head><body> <button onclick="fun()">请点击这里</button> <script> var test = outfun(1); function fun() { test(10); } function outfun(x) { var tmp = 1; return function infun(y) { alert(x + y + (++tmp)); } //这样才是闭包 } </script></body></html>
这里每次点击后结果都会加1
第一次点:
第二次点:
当然, 我们也可以使用全局变量来调用闭包
再来看一个例子
function f1(){ var n=999; nAdd=function(){n+=1}//所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去 function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd 的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。看下面这段代码:
function a() { var i = 0; function b() { alert(++i); } return b;}var c = a();c();
这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
看完了上面,闭包其实在json中也可以来使用,这种方法在很多框架中还经常见到,最基础如下:
<script>var aaa = (function(){ var a = 1; function bbb(){ a++; alert(a); } function ccc(){ a++; alert(a); } return { b:bbb, //json结构 c:ccc }})();aaa.b(); //2aaa.c() //3</script>
这里使用了json,返回是一个json
我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,
那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。
var CachedSearchBox = (function(){ var cache = {}, count = []; return { attachSearchBox : function(dsid){ if(dsid in cache){//如果结果在缓存中 return cache[dsid];//直接返回缓存中的对象 } var fsb = new uikit.webctrl.SearchBox(dsid);//新建 cache[dsid] = fsb;//更新缓存 if(count.length > 100){//保正缓存的大小<=100 delete cache[count.shift()]; } return fsb; }, clearSearchBox : function(dsid){ if(dsid in cache){ cache[dsid].clearSelection(); } } }; })(); CachedSearchBox.attachSearchBox("input");这样我们在第二次调用的时候,就会从缓存中读取到该对象,如果上面的例子看不懂,那就看下面的吧
var db = (function() {// 创建一个隐藏的object, 这个object持有一些数据// 从外部是不能访问这个object的var data = {};// 创建一个函数, 这个函数提供一些访问data的数据的方法return function(key, val) { if (val === undefined) { return data[key] } // get else { return data[key] = val } // set }// 我们可以调用这个匿名方法// 返回这个内部函数,它是一个闭包})();db('x'); // 返回 undefineddb('x', 1); // 设置data['x']为1db('x'); // 返回 1// 我们不可能访问data这个object本身// 但是我们可以设置它的成员
三、使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便
改变父函数内部变量的值。
- JavaScript闭包研究
- Javascript闭包的一些研究
- Javascript闭包的一些研究
- 研究闭包实例
- 【JavaScript】Javascript闭包
- 关于JavaScript的执行域,标识符解析,闭包的研究
- js闭包的研究
- javascript的闭包javascript
- Javascript闭包演示javascript
- [ javascript ] javascript闭包测试!
- 【javascript】javascript中的闭包
- 【javascript】学习Javascript闭包
- 理解 JavaScript 闭包
- javascript 闭包
- javascript闭包
- Javascript闭包
- JavaScript中的"闭包"
- JavaScript 闭包
- 7.映射和集合类型(射…让人总是浮想)
- 安全参透之旅第2章 fierce工具使用
- lightoj 1356 - Prime Independence 【质因子分解 奇偶构图 + HK优化】
- ftp配置
- 数据库增删改查基本语句
- JavaScript闭包研究
- protobuf-安装篇
- oracle数据库使用Datagrid 数据列表的分页
- Sqlite之外键约束跟内外联表
- leetcode 23:Merge k Sorted Lists
- LDAP 认证服务可用性监测
- Foundation 之 NSDictionary和NSMutableDictionary
- 关于服务器端跳转和客户端跳转
- Mysql cookbook 2