作者:king1994 | 来源:互联网 | 2023-10-11 10:55
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>123li>
<li>456li>
<li>789li>
<li>010li>
ul>
js代码:(错误方式)
window.Onload= function(){
var lis = document.getElementsByTagName('li');
var len=lis.length;
for (var i=0;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){
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){
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){
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){
(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 动画实现原理,就是闭包的一个典型应用的呀;