为什么点击都打印出6,而不是0,1,2,3,4,5 闭包的问题?

发布于 2022-09-06 21:14:18 字数 463 浏览 14 评论 0

<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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

余生再见 2022-09-13 21:14:18

这个涉及到js作用域以及js的运行机制。你把这些基础知识弄明白了,就不会感觉奇怪了。
在es6之前是没有块级作用域的概念的,只有全局作用域和函数作用域,所以这里有两种作用域,click回调的函数作用域,全局作用域(for循环不会产生块级作用域),也就是说i属于全局作用域。click回调里面调用了i值,但里面并没有定义,这个变量就叫做自由变量,js对自由变量取值的逻辑是会沿着作用域链向上寻找,直到找到值,或找不到值为止,当你点击触发回调的时候,函数作用域内没有该变量就会向上寻找,即全局作用域,此时全局作用域中的i值已经为6了(这一点看明白,很重要)。所以你log数出来的每次都是6。

挽你眉间 2022-09-13 21:14:18

es6:

  var items = document.querySelectorAll("li");
  for(let i = 0; i<items.length;i++){
    items[i].onclick = function(){
      console.log(i)
    } 
  }

es5:

  var items = document.querySelectorAll("li");
  for(var i = 0; i<items.length;i++){
   (function(i){
        items[i].onclick = function(){
      console.log(i)
    } 
   })(i)
  }

for循环直接就运行了跑了6次,等你点击的时候i已经等于5

就此别过 2022-09-13 21:14:18

那for循环进行的时候,是怎么运行的呢?
i=0时,是console.log(0) 吗 还是console.log(i)?

  1. for 循环在你一打开,或者浏览器一编译的时候,已经运行了。由于你没点击,于是没有触发 console.log(i);
  2. i 是全局的 i; 是 for()里面的i;所以点击 item[i]会打印出循环6次结束的 i.
水晶透心 2022-09-13 21:14:18
var items;
var i;
items = document.querySelectorAll("li");
for(i = 0; i<items.length;i++){
    items[i].onclick = function(){
      console.log(i)
    }    
 }

这样拆开,其实都一样的,for循环是没有作用域的,var定义的变量会提升到外面。这样最后i就是6,你点击的时候输出就是6.

高冷爸爸 2022-09-13 21:14:18

因为你点击的时候,循环已经结束

故人爱我别走 2022-09-13 21:14:18

先说你想达到预期 可以 改为let 他输出结果为0 1 2 3 4 5

你结果是因为js事件处理器在线程空闲时间不会运行,导致最后运行的时候输出的都是i最后的值

其实你这么理解 for循环是一瞬间执行的 属于主线程 事件处理器是在触发的时候才会触发 而此时触发的的时候 i的值已经为6(不符合循环条件时候i 为 6 ) 所以你事件触发输出的会全是6

瀞厅☆埖开 2022-09-13 21:14:18
var items = document.querySelectorAll("li");
for (var i = 0; i < items.length; i++) {
    items[i].onclick = function () {
        console.log(i)//永远是6
        console.log($(this).index())//打印当前点击的元素的索引
    }

}
泡沫很甜 2022-09-13 21:14:18
var items = document.querySelectorAll("li");
  for(var i = 0; i<items.length;i++){
      items[i].index=i;
    items[i].onclick = function(){
      console.log(this.index)
    } 
  }

不是闭包,for循环又不等你点击的时候才循环,当然都是最后一个

无远思近则忧 2022-09-13 21:14:18

在你点击的时候,已经运行结束了,你需要点击之后将你要打印的变量保存下来(也就是先获取相对应的i的元素),再进行输出

尴尬癌患者 2022-09-13 21:14:18

最简单的,把 var 改成块级作用域.
for(let i = 0; i<items.length;i++){

items[i].onclick = function(){
  console.log(i)
} 

}

你的笑 2022-09-13 21:14:18

这就是循环的,不是闭包,使用let 或者点击的时候通过$(this).index()

吐个泡泡 2022-09-13 21:14:18

兄弟你是循环绑定事件,当你循环结束了并未触发任何事件,但是循环结束了,所以每个事件绑定上的都是最后一次循环的数值。事件会等到你触发事件了再继续执行function内容,而for循环可不会等你~

颜漓半夏 2022-09-13 21:14:18

涉及到变量提升的 点击的时候已经结束循环 使用es6的let可以解决

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文