<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <button class="btn1"> 踩坑1 </button> <button class="btn1"> 踩坑2 </button> <button class="btn1"> 踩坑3 </button> <button class="btn1"> 踩坑4 </button> <script> var buttons1 = document.getElementsByClassName('btn1'); /* (function(){ for(var i=0; i<buttons1.length; i++){ var btn = buttons1[i]; btn.onclick = function(){ alert(i); } } })(); */ //上面这段代码看上去是没问题的,为什么会每次点击都是4呢 //换个写法,上面的自执行函数等价于下面这种写法 //讨论下闭包是什么 function bindBtn1(){ for(var i=0; i<buttons1.length; i++){ var btn = buttons1[i]; /*Javascript中,没有块级作用域,只有函数作用域。所以在函数中定义的变量,
是只可以在函数内部被访问到的,包括在函数内部定义的子函数。 所以内部函数clickFunc能访问到父函数的变量 i */ var clickFunc = function(){ alert(i); } /*如果内部函数存在被外部调用的可能,
那么内部函数能访问到的外部函数的成员变量是不应该被Javacript引擎回收掉内存空间的。 在这里clickFunc有被外部btn1点击访问的可能,
所以他的父函数bindBtn1的内存空间在执行完成后是不会被回收内存的, 因此clickFunc继续享有了父函数bindBtn1作用域的变量访问权限, *并且这个函数作用域在外部是不能被外界访问到的,
是封闭的,被内部函数clickFunc所独享的,因此bindBtn1形成了一个闭包。 *从本质上来说,闭包的形成是利用了Javacript内存回收机制,
得到的一个封闭的内存块,这与Java中的一个对象是不是十分相似呢 */ btn.onclick = clickFunc; //这是内部函数的一个伟大的逃脱 } } bindBtn1(); var viewbtn1 = buttons1; //那么来分析一下为什么,点击踩坑按钮每次都会输出同一个数字,而不是递增的数字呢 //调试看看button1[0] 的onclick函数 /* onclick : function arguments : null caller : null length : 0 name : 'clickFunc' ...... ###########看看作用域########### [[scope]] : scopes[2] 0 : Closure (bindBtn1) * 闭包作用域 i = 4 i : 4 1 : Globle * 全局作用域 ... ################################ */ /************************************************************************ 重点来了:注意 Closure (bindBtn1) * 闭包作用域 i = 4 i : 4 内部函数的作用域除了全局作用域外,还有bindBtn这个闭包作用域。 原来是这样,这几个内部函数 clickFunc 共用了一个闭包作用域啊!!! 所以能访问到的 i 其实是一个。 所以每次点击按钮显示的 i 永远是一样的。 那么如何解决这个问题呢,看看下面吧 *************************************************************************/ </script> <br/> <button class="btn2"> 填坑1 </button> <button class="btn2"> 填坑2 </button> <button class="btn2"> 填坑3 </button> <button class="btn2"> 填坑4 </button> <script> var buttons2 = document.getElementsByClassName('btn2'); function bindBtn2(){ for(var i=0; i<buttons2.length; i++){ //要解决这个问题,我们需要让内部函数不能共享同一作用域 //所以为每个内部函数创建不同的闭包作用域 /* (function(j){ var btn = buttons2[j]; btn.onclick = function(){ alert(j); } })(i); */ //上面代码等价于下面的 : function selfClosure(j){ var btn = buttons2[i]; var clickFunc = function(){ alert(j); } btn.onclick = clickFunc; } selfClosure(i); } } bindBtn2(); var viewbtn2 = buttons2; /************************************************************************ 调试 buttons2[0] 的onclick函数 onclick : function arguments : null caller : null length : 0 name : 'clickFunc' ...... ###########看看作用域########### [[scope]] : scopes[3] 0 : Closure (selfClosure) * 闭包作用域 selfClosure j : 0 1 : Closure (bindBtn1) * 闭包作用域 bindBtn1 i : 4 2 : Globle * 全局作用域 ... ################################ 现在每个内部函数都有了私有的selfClosure闭包作用域,
独享作用域中的j变量,所以就解决了上述问题。 *************************************************************************/ </script> </body> <html>