打脸了,这并不是闭包的问题,而是一个事件循环机制
以下为错误解释
这是一个关于变量闭包的问题,以前做项目时遇到,那时候并没有想明白,换了另一种方法实现,今天看闭包的知识点时恍然大悟,于是,写出来记录下。
首先,主要涉及两个概念
变量的作用域:也就是变量的有效范围,函数内部变量的作用域也就只能在函数内部使用。
变量的生存周期:对于函数的局部变量,函数退出后也就失去了价值,他们也会随着函数调用的结束而销毁。
然后,上闭包应用。
假设页面上有5个div节点,我们通过循环来给每个div绑定onclick事件,按照索引顺序,点击第1个div时弹出0,点击第2个div时弹出1,以此类推。如果用常规的绑定就会出现题目中的问题。
原因:div节点的onclick事件是被异步触发的,当事件被触发的时候,for循环早已结束,此时变量i的值已经是5,所以在div的onclick事件函数中顺着作用域链从内到外查找变量i时,查找到的值总是5(注释部分代码可以尝试一下)。
解决办法:在闭包的帮助下,把每次循环的i值都封闭起来。当在事件函数中顺着作用域链中从内到外查找变量i时,会先找到被封闭在闭包环境中的i,如果有5个div,这里的i就分别是0,1,2,3,4:
最后,上代码,结合以上解释。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>闭包</title>
</head>
<style type="text/css">
div {
width: 100%;
height: 50px;
margin: 20px 0;
border: aqua 1px solid;
background: #00FFFF;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
div:hover {
background: chartreuse;
}
</style>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</body>
<script type="text/javascript">
var nodes = document.getElementsByTagName('div');
/* 未使用闭包前 */
// for(var i=0,len=nodes.length; i<len; i++) {
// nodes[i].onclick = function() {
// alert(i);
// }
// }
for(var i=0,len=nodes.length; i<len; i++) {
(function(i){
nodes[i].onclick = function() {
alert(i);
}
})(i)
}
</script>
</html>
效果截图: