为什么点击都打印出6,而不是0,1,2,3,4,5 闭包的问题?
<ul>
<li>选项1</li>
<li>选项2</li>
<li>选项3</li>
<li>选项4</li>
<li>选项5</li>
<li>选项6</li>
</ul>
<style>
li{
border: 1px solid;
}</style>
</body>
<script>
var items = document.querySelectorAll("li");
for(var i = 0; i<items.length;i++){
items[i].onclick = function(){
console.log(i)
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
这个涉及到js作用域以及js的运行机制。你把这些基础知识弄明白了,就不会感觉奇怪了。
在es6之前是没有块级作用域的概念的,只有全局作用域和函数作用域,所以这里有两种作用域,click回调的函数作用域,全局作用域(for循环不会产生块级作用域),也就是说i属于全局作用域。click回调里面调用了i值,但里面并没有定义,这个变量就叫做自由变量,js对自由变量取值的逻辑是会沿着作用域链向上寻找,直到找到值,或找不到值为止,当你点击触发回调的时候,函数作用域内没有该变量就会向上寻找,即全局作用域,此时全局作用域中的i值已经为6了(这一点看明白,很重要)。所以你log数出来的每次都是6。
es6:
es5:
for循环直接就运行了跑了6次,等你点击的时候i已经等于5
那for循环进行的时候,是怎么运行的呢?
i=0时,是console.log(0) 吗 还是console.log(i)?
这样拆开,其实都一样的,for循环是没有作用域的,var定义的变量会提升到外面。这样最后i就是6,你点击的时候输出就是6.
因为你点击的时候,循环已经结束
先说你想达到预期 可以 改为let 他输出结果为0 1 2 3 4 5
你结果是因为js事件处理器在线程空闲时间不会运行,导致最后运行的时候输出的都是i最后的值
其实你这么理解 for循环是一瞬间执行的 属于主线程 事件处理器是在触发的时候才会触发 而此时触发的的时候 i的值已经为6(不符合循环条件时候i 为 6 ) 所以你事件触发输出的会全是6
不是闭包,for循环又不等你点击的时候才循环,当然都是最后一个
在你点击的时候,已经运行结束了,你需要点击之后将你要打印的变量保存下来(也就是先获取相对应的i的元素),再进行输出
最简单的,把 var 改成块级作用域.
for(let i = 0; i<items.length;i++){
}
这就是循环的,不是闭包,使用let 或者点击的时候通过$(this).index()
兄弟你是循环绑定事件,当你循环结束了并未触发任何事件,但是循环结束了,所以每个事件绑定上的都是最后一次循环的数值。事件会等到你触发事件了再继续执行function内容,而for循环可不会等你~
涉及到变量提升的 点击的时候已经结束循环 使用es6的let可以解决