<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>