分分钟搞懂JS-闭包函数
1 //抛开概念!直接上代码,看实例 2 3 var i=100; 4 function add1(){ 5 alert(i); 6 i++; 7 } 8 function add2(){ 9 var j=100; 10 alert(j); 11 j++; 12 } 13 14 //测试; 15 16 // add1(); //100 17 // add1(); //101 18 // add1(); //102 19 // 20 // add2(); //100 21 // add2(); //100 22 // add2(); //100 23 24 /*为什么呢 原因很简单 25 i 是全局变量,只有页面关闭的时候,才会被GC回收; 26 j 是局部变量,函数执行完毕后就 被GC 回收; 27 28 问:有没有办法将j 变成"全局变量"呢? 29 A同学答:有,将j写在外面(尼玛,傻逼啊) 30 B同学答,用return(有点接近了) 然后用全句变量来接收; 31 C同学答:闭包(完美) 32 */ 33 function add3(){ 34 var j=100; 35 function fun(){ 36 alert(j); 37 j++; 38 } 39 return fun; //注意这里; 40 } 41 42 /* 43 测试: 44 45 var obj=add3(); //执行add3()函数,同时返回了fun的引用(也就是fun的函数体) 46 47 //直接alert(obj) 你会看到他的函数体- function fun(){....} 再加上一个括号(),就可以执行了 48 49 obj(); //100 50 51 obj(); //101 52 53 obj();//102 54 55 */
当函数a的内部函数b 被函数a 外的一个变量引用的时候,就创建了一个闭包。
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。
那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收
最后,如果你能看懂这段代码你就理解了闭包!
1 var name="window"; 2 var object={ 3 name:"my object", 4 getName:function (){ 5 return function (){ 6 return this.name; 7 } 8 } 9 10 } 11 alert(object.getName()()); //window
闭包的多种写法:
写法一:
function f1(){ var index=1; function f2(){ alert(index); index++; } return f2; } //调用 var test=f1(); test(); //1 test(); //2 test(); //3
写法二:
function outer(){ var index=1; return function(){ //使用匿名函数 alert(index); index++; } } var bibao=outer(); bibao(); bibao(); bibao();
写法三:
var outer=(function (){ var index=1; return function (){ alert(index); index++; } })(); outer(); outer(); outer();
写法四:
var outer=null; (function (){ var index=1; function inner(){ alert(index++); }; outer=inner; })(); outer(); outer(); outer();
总之就是函数之间的嵌套,变量之间的互相引用;
javascript
的垃圾回收原理
(1)、在javascript
中,如果一个对象不再被引用,那么这个对象就会被GC
回收;
(2)、如果两个对象互相引用,而不再被第3
者所引用,那么这两个互相引用的对象也会被回收。
总结:
实例:
html代码:
<ul> <li>123</li> <li>456</li> <li>789</li> <li>010</li> </ul>
js代码:(错误方式)
window.onload = function(){ var lis = document.getElementsByTagName('li'); var len=lis.length; for (var i=0;i<len;i++){ lis[i].onclick = function(){ //当点击时for循环已经结束 alert(i); }; } }
js代码:(错误方式)
window.onload=function (){ var index=0; var lis=document.getElementsByTagName("li"); var len=lis.length; for(var i=0;i<len;i++){ lis[i].onclick=function (){ alert(index); //这样做,避免了i直接等于3,但是,却没有绑定到指定的对象上滴呀 index++; if(index==len){ index=0; } } } }
js代码:(改进方式一)面向对象+this关键字的使用
window.onload=function (){ var lis=document.getElementsByTagName("li"); var len=lis.length; for(var i=0;i<len;i++){ lis[i].index=i; //给每个变量动态的绑定一个属性,并赋值 lis[i].onclick=function (){ var temp=this.index; //然后使用this关键字; alert(temp); } } }
js代码改进二:让i独立出来,index作为他的一个“副本”! i的变化不再影响到我们index
function showInfo(obj,index){ obj.onclick=function (){ alert(index); } } window.onload=function (){ var lis=document.getElementsByTagName("li"); var len=lis.length; for(var i=0;i<len;i++){ showInfo(lis[i],i);//i的改变和 index无关滴呀 } }
原理解析一:
var index=1; function change1(){ index=index+1; } function change2(){ index=index+2; } change1(); change2(); alert(index); //4
原理解析二:
function change1(val){ var temp=val; temp=temp+1; } function change2(val){ var temp=val; temp=temp+2; } change1(index); change2(index); alert(index); //这样这不会改变;
最总版本:(关键-传递副本)
var index=1; (function (val){ val=100; })(index); (function (val){ val=10000; })(index); alert(index);
js代码:(闭包实现)模块化代码,减少全局变量的污染-最好的方式;
我们需要在每次循环时为变量 i
值创建一个拷贝,重点在:模块话代码,形成一个独立的区域;
window.onload=function (){ var lis=document.getElementsByTagName("li"); var len=lis.length; for(var i=0;i<len;i++){ (function (e){ lis[e].onclick=function (){ alert(e); } })(i); //形成一个独立的区域互补干扰 } }
继续扩展,这段代码是不是闭包?还是仅仅是一个你们匿名函数的自执行呢?
(function (e){ lis[e].onclick=function (){ alert(e); } })(i)
//闭包概念:闭包是指某种程序语言中的代码块允许一级函数存在并且 //在一级函数中所定义的自由变量不能被释放,直到一级函数释放前, //一级函数外也能应用这些未释放的自由变量; var shit=function (y){ var x=y; return function (){ alert(x++); //这里调用了一级函数的局部变量x //上下连个交换着尝试 alert(y--); //这里调用参数变量,是自变量; }}(5); shit(); // 5 5 shit(); // 6 4 shit(); // 7 3
关于内存泄露的问题;
function closure(){ var div=document.getElementById("div1");//div用完之后一直驻留在内存中 div.onclick=function (){ alert(div.innerHTML); //这里导致了内存泄露得呀 //长期扎住在内存中得,没有得到是释放; } } //优化: function closure2(){ var div=document.getElementById("div1"); var text=div.innerHTML; div.onclick=function (){ alert(text); //这里导致了内存泄露得呀 //长期扎住在内存中得,没有得到是释放; } div=null; }
再推荐一篇关于闭包的好文章
http://segmentfault.com/a/1190000000652891
应用
看我另外一篇文章:
js 动画实现原理,就是闭包的一个典型应用的呀;