早上吃了份小笼包,今天就来讲闭包吧😁

305 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

通过一个需求来了解

需求:点击某个按钮, 提示点击的是第n个按钮

错误做法

<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<script type="text/javascript">
 var btns = document.getElementsByTagName('button')
 for (var i = 0,length=btns.length; i < length; i++) {
   var btn = btns[i]
   btn.onclick = function () {  //遍历加监听
     alert('第'+(i+1)+'个')     //结果 全是[4]
   }
 }
</script> 

错误原因:直接修改并使用全局变量[i],导致for循环结束后,所有点击按钮绑定的弹窗值都是[i+1],随后调用时,都会找到[i]这个全局变量,但是此时i==3,所以所有结果都是4 动画2.gif 可能有朋友已经想到用let或者给btn对象加个属性保存i值了,但是为了学习闭包,这里将会用闭包的思维来解决,在展示代码之前,我们先认识什么是闭包。

闭包

闭包是嵌套的内部函数,当一个嵌套的内部(子)函数应用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包。

产生闭包的条件

  • 函数嵌套

  • 内部函数引用了外部函数的数据(变量/函数) 作用

  • 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)

  • 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

闭包做法

 //利用闭包
 for (var i = 0,length=btns.length; i < length; i++) {
    //此处的j是局部的,它将传入的[i]存入局部的[j]中,这样就能实现效果 
   (function (j) {
     var btn = btns[j]
     btn.onclick = function () {
       alert('第'+(j+1)+'个')
     }
   })(i)
 }

动画3.gif 因为(function (j) {})(i)内部嵌套了一个function () {alert('第'+(j+1)+'个')},且内部函数运用了外部函数的变量(i),所以闭包就形成了,因为闭包的特点:使用函数内部的变量在函数执行完后, 仍然存活在内存中,所以,循环执行(function (j) {})(i)之后,该函数的形参j(即每次循环传进来的i)依然存在内存中,所以每次调用都是想要的值(i)。

闭包的缺点

  • 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
  • 容易造成内存泄露 解决:
  • 能不用闭包就不用
  • 及时释放

一条简单面试题

var name = "The Window";
var object = {
 name : "My Object",
 getNameFunc : function(){
   var that = this;
   return function(){
     return that.name;
   };
 }
};
alert(object.getNameFunc()()); //?  

解析:这个比较简单,that被function(){return that.name;}使用,所以保存的是object里的this值,所以输出的是object的name(My Object)。