详解JS中的闭包

Javascript ZackZhong 1204℃ 0评论

可以先看这篇JS中函数的各种叫法

JS中的闭包:
所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),
因而这些变量也是该表达式的一部分。看不懂了把?·········其实我也看不懂!!
一直很羡慕那些给变量取名字的科学家,因为只有他们才能轻松理解那个词说的是什么·······

闭包的作用:
1) 函数外面可以访问函数内部的局部变量
2) 使变量所占的内存不被释放
根据作用域链和变量的生存期我们知道,变量只能沿着作用域链向上(即函数内可以访问函数内的变量
,而函数外部不能访问函数内定义的局部变量)查找,反之则不可以

而局部变量在函数执行完成后就销毁了。而闭包的存在,使得这两点变的可能

闭包的原理:根据JS中的垃圾回收机制,当一个对象没有变量来引用的时候,它就将会被回收.
闭包中,外部变量引用了内部变量,使得变量保存了下来,这是我肤浅的理解,实际上不一定时这样。

我们来看几个小例子:
我们想用一个变量来统计某个方法执行的次数
例子1:
<script>
  var count=0; //定义一个全局变量
  function test(){
   count++;
  return count;
  }
 alert(test()); //1
 alert(test()); //2
 alert(test()); //3
 虽然这样做能实现效果,但容易污染全局变量,来考虑其他方法
</script>
例子2
<script>
 function test(){
  var count=0;
   count++;
   return count;
 }
alert(test()); // 1
alert(test()); // 1
alert(test());// 1
我们发现,三次都弹出1,这是因为count为局部变量的原因,每一次执行,都会从新定义并赋值为0.
</script>

例子3: 使用闭包实现累加方法1:
<script>
function box(){
  var age=100;
    return function(){ //返回一个匿名函数,这就产生了闭包
      age++;
      return age;
   };
 }
var b=box();
alert(b());//101
alert(b());//102
alert(b());//103
alert(b); //funciton(){age++;return age;}

============华丽的分割线==============

/* 方法2:
除了返回一个匿名函数,我们可以将匿名函数赋值给一个全局变量,
这样,全局变量引用了那个匿名函数,而匿名函数内部又使用了a变量,
所以整个函数的执行环境保留了下来,局部变量age的值就一直保留了下来
*/
var c;
function box(){
   var age=100;
   c= function(){ // 包匿名函数直接赋值给一个全局变量,也产生了闭包
   age++;
   alert(age);
  };
}
box();//执行一次方法box,将匿名函数复制给全局变量c
c();//101
c();//102
c();//103

</script>

闭包的典型应用,据说经常会出面试题。在循环中直接找到对应元素的索引
例子:给ID为ul1 的UL下的四个Li,让每个li点击时弹出自己的索引,如点击第一个li弹出0 等

常规思路:遍历li,给每个Li添加点击事件,同时弹出i
var ul1=document.getElementById("ul1");
var aLi=ul1.getElementsByTagName("li");
for(var i=0;i<aLi.length;i++){
    aLi[i].onclick=function(){
     alert(i);
  };
}
cosnole.log(i); // 4 整个for循环结束后,i并没有被销毁,因为他是全局的!!

看起来没有问题,执行后我们发现,无论点击那个li,都是弹出的 4
那么 4 是哪了来的呢??
这还是变量的作用域和生存期的原因,我们知道,JS中不存在块作用域,在for循环li定义的i
其实就是全局的,当每一个li点击时,执行alert(i) ,i就会根据作用域链去查找,找到的就是那个全局的i
所以都弹出的是4.也就是说,每一个li访问到的其实是同一个i
解决办法:让每一个Li都有一个自己的i

使用闭包来解决:
var ul1=document.getElementById("ul1");
var aLi=ul1.getElementsByTagName("li");
for(var i=0;i<aLi.length;i++){
//使用一个即时函数
   (function(i){
      aLi[i].onclick = function(){
      alert(i);
   };
 })(i);
/*
也可以这样:闭包的存在,使得j保留下来了
aLi[i].onclick=(function(){
     var j=i; 每一个Li都有一个自己的j
     return function(){
     alert(j);
 };
})();

*/
}

当然,闭包还有很多应用,这里只是举个简单的例子。
闭包的使用也会带来一些问题:比如大规模使用闭包可能导致内存泄漏等问题。
你理解闭包了吗?

转载请注明:副业 and 脱单研究所 » 详解JS中的闭包

喜欢 (11)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址