js闭包

js闭包-----浅谈



接触js也有一段时间了,最近看了一些关于闭包的问题,不是很理解,就决定花一点时间去弄懂它。于是乎在网上查阅了大量的资料,看了很多例子。接下来简单的讲一下我对闭包的理解。
首先我们学一个知识点之前,肯定要思考的一个问题就是我们为什么要去学它?它到底有什么用?能解决什么问题?

什么是闭包?

“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
相信很少有人能直接看懂这句话,因为他描述的太学术。我想用如何在Javascript中创建一个 闭包 来告诉你什么是闭包,因为跳过闭包的创建过程直接理解闭包的定义是非常困难的。看下面这段代码:
function a(){
 var i=0;
 function b(){
 alert(++i);
 }
 return b;
}
var c = a();
c();
这段代码,有两个特点:
1.在函数a里面嵌套了一个函数b
2.函数a返回了函数b

这样就是一个简单的闭包。
a函数里面定义了一个局部变量i ,因为这是一个局部变量,一般会在函数执行完毕之后,被销毁,但是由于i在函数b中被引用,
而函数b又被return,被赋值给了全局变量c。所以当函数a执行完之后,i不会被销毁。
你可以在上面的代码下继续执行函数c就会弹出2,3,4,5.因为此时变量i依然存在而且保留着上一次执行完之后的数据。

闭包有什么用?

相信看了上面的一个例子,我们就能知道得到这个答案。
闭包能在函数外部,访问函数的局部变量,能使变量始终存在内存中。
再以一个简单的例子说明一下:
var ulo = document.getElementById('ulo');
var lio = ul.getElementsByTagName('li');
for(var i = 0;i<10;i++){
 lio.addEventListener('click',function(){ 
     alert(i);
   })
}

假设html为:
<ul id="ido">
   <li></li>
   ......
</ul>


上面的js代码为10个li绑定了事件,但是真正执行时,会发现无论我点哪一个li结果都会alert(9);
因为当我们点击li时这段代码已经执行完一遍了,此时的i已经是9了,所以当我们点击任何一个li都会弹出9。
解决方法:
var ulo = document.getElementById('ulo');
var lio = ulo.getElementsByTagName('li');
for(var i = 0;i<10;i++){
  !function(i){
     lio.addEventListener('click',function(){
       alert(i)
    })
  }(i)
}
此时的i不会去向外部的i去获取(因为此时外部的i值已经是执行完之后的值了)。而是通过闭包保存该i值,这个值就是当时的i值,当点击时,会向即时函数获取i值,也就是被保存起来的那个i值。

js的垃圾回收机制

在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
所以闭包的使用要慎重,要在不使用时,释放变量,防止内存泄漏。


好了,这就是我现阶段对于闭包的理解,可能还有些偏差,也不是很全面,不喜勿喷,我也会在之后做相应的更新。希望能对一些小伙伴有所帮助。


下面的是补充:

前面讲的可能还是有有点笼统,后来我又去查了一些文档,再来稍微详细的讲一下,那个例子:
var arr = []
for(var i = 0;i<10;i++){
     arr[i] = function(){
         alert(i) 
    }
}



这样的代码,在执行arr1-9时输出的都是10。
这么理解呢?
首先在全局作用域中会有变量arr,和变量i
然后·执行for循环,给arr赋值,这时的程序不会去看function里面的东西,因为这只是一个赋值,但是此时的arr[i]的作用域链已经确定了,就是GO全局作用域
然而当执行的时候alert(i) 这句语句时,会去arr[i]的作用域中找变量 i 此时的i已经是10了,所以输出10.

怎么解决这个问题?
var arr = []
for(var i = 0;i<10;i++){
  (function(j){
     arr[j] = function(){
         alert(j) 
    }
   }(i))
}

这样写有什么好处呢?
其实是在每次赋值时,使用立即执行函数,形成了新的作用域并且把每次循环的i都保存了下来,此时在进行赋值操作时的arr[i]的作用域链,就不止全局作用域了,还有立即执行的那个函数的作用域,在那个作用域中保存了i也就是形参j,所以在每次执行时,都能取到被保存的值。


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值