当前位置: 首页 > 知识库问答 >
问题:

javascript - 一个关于 for 和 onclick() 事件的问题?

武彭薄
2024-02-20

一个学习案例中遇到的问题

index.html

<div class="d-flex gap-3">    <div class="box"></div>    <div class="box"></div>    <div class="box"></div></div>

index.css

.box {    width: 100px;    height: 50px;    border: 1px solid;}

index.js

var boxs = document.getElementsByClassName('box');for (var i = 0; i < boxs.length; i++) {    boxs[i].onclick = function () {  // i = 1,2,3        console.log(i); // i = 3    }}

上述代码中, 我在循环里为每个 .box 添加点击事件, 但是在事件里的i始终是循环体执行完毕后的结果 3, 为什么会出现这种情况?

因为之前写代码在 onclick 事件里基本都是用 this, 或者用 let 来代替 var 来定义变量, 所以绕过了这个坑
但现在遇到了这样的 bug, 还是想问下导致这个问题的原因是什么?

补充

关于 var 的特性, 我能想到的是 全局污染和变量提升, 简单地说

  • 全局污染: for 中定义 var, 作用域会提升到全局
  • 变量提升: 允许先调用后定义

但是上述两个特性都不能合理的解释 -> 为什么在for循环中定义的onclick, 循环变量i在onclick事件中永远是for最终执行后的i?

共有5个答案

屠君墨
2024-02-20

补充下,这题知识点是js 的作用域, 点击按钮的时候打印i, js引擎会去找click函数外部的作用域,变量i 的值。然而触发click事件时,<script> 引入的代码早就执行完了【此时i 为3】。你打个断点去chorme debugger, 一步步执行下就可以理解了。js 知识内容建议去看《JavaScript忍者秘籍》。

鲜于峰
2024-02-20

这个循环转化这样就好理解了

var i = 0;{    boxs[i].onclick = function () {          console.log(i); // i = 3    }}++i;{    boxs[i].onclick = function () {          console.log(i); // i = 3    }}++i;{    boxs[i].onclick = function () {          console.log(i); // i = 3    }}

如果我们使用的是let,可以这样理解

{     let t = 0;    {            let i = t;        boxs[i].onclick = function () {              console.log(i); // i = 3        }    }    ++t;    {        let i = t;        boxs[i].onclick = function () {              console.log(i); // i = 3        }    }    ++t;    {        let i = t;        boxs[i].onclick = function () {              console.log(i); // i = 3        }    }}
陆昊
2024-02-20

补充一个比较好理解的

var i = 0;console.log(i); // 0var i = 3;

上述代码中输出的 i = 0, 因为 console.log() 是同步方法, 当它执行完毕后才会执行下面的 i = 3


var i = 0;boxs[i].onclick = function() {    console.log(i); // 3}var i = 3;

而在 onclick 中, 因为是一个异步方法, 所以执行到时不会发生阻塞, 而是同时执行了 i = 3, 导致最终 click 触发时 i 的值已经是 3 了

林玮
2024-02-20

你换个思路,在你的代码中有几个i呢,是不是只有一个,所有当for循环结束i的值也只能是一个,因为i一个变量不可能同时又是1又是2又是3

孔欣可
2024-02-20

这个问题的原因是 JavaScript 的变量提升(Hoisting)特性。

在 JavaScript 中,变量的声明会被提升到其所在作用域的顶部,但赋值操作不会。在你的代码中,var i 这一行代码被提升到了循环的顶部,但赋值 i = 0i = 1i = 2 这些操作并没有被提升。

所以,当你在循环中点击 .box 元素时,实际上 i 的值已经被设为了 3。这是因为循环结束后,i 的值已经变成了 3,并且这个值被赋给了每个 .box 元素的 onclick 事件处理器。

如果你希望在事件处理器中 i 的值是 012,你需要将 var i 改为 let i。使用 let 关键字声明的变量有块级作用域,并且不会发生变量提升。这样,每个 .box 元素的 onclick 事件处理器都会在其自己的作用域中获取到正确的 i 值。

以下是你的代码,其中将 var i 改为了 let i

<div class="d-flex gap-3">    <div class="box"></div>    <div class="box"></div>    <div class="box"></div></div>
.box {    width: 100px;    height: 50px;    border: 1px solid;}
var boxs = document.getElementsByClassName('box');for (let i = 0; i < boxs.length; i++) {    boxs[i].onclick = function () {  // i = 0,1,2        console.log(i); // i = 0,1,2    }}
 类似资料:
  • 上面是代码,想执行'person1.func3()'。 结果如下图

  • 关于正则的一个小问题 /#\/((\w)+)/.exec("/a-web/#/abc?") 返回值是  ['#/abc', 'abc', 'c', index: 7, input: '/a-web/#/abc?', groups: undefined] 数组第二项是匹配项(\w+) 返回 'abc' 数组的第三项 返回值 'c'怎么理解啊 没啥尝试

  • 我已经开始做一个游戏,有点类似于“花比尔盖茨的钱”,但我说过要稍微改变一下。我做了第一项,我试着用JS编辑它,所以每次你按“买”,它会从你身上移除1美元,或者,当你按“卖”给你1美元。问题是,每次我点击,它只算一次。另外,如果我按“买进”,然后按“卖出”,它会立即给我11美元,而不是10美元。文件名:index.html 文件名:script.js

  • 问题1: 类似微信这样的安装在用户个人设备上的软件,调整了后端接口服务后,需要用户更新设备上的软件,如果用户没更新,还是能正常使用,一般这种是采取什么方案处理的?是调整后的接口服务,仍然支持旧版本的软件使用吗? 问题2: 假设我有个web系统,全国各地都有门店在使用,有些门店需要使用频繁更新后的web系统(),有些门店只需要偶尔更新web系统。这些门店使用的web系统都是同一个域名。有什么方案,在

  • 本文向大家介绍JavaScript中关于base64的一些事,包括了JavaScript中关于base64的一些事的使用技巧和注意事项,需要的朋友参考一下 base64 其实是一种编码转换方式, 将 ASCII 字符转换成普通文本, 是网络上最常见的用于传输8Bit字节代码的编码方式之一。 base64 由字母 a-z 、 A-Z 、 0-9 以及 + 和 / , 再加上作为垫字的 = , 一共6

  • 问题内容: 我在一个div内放了一个嵌入式Flash电影,在主div上放了一个javascript onclick事件处理程序,但是没有捕捉到点击,这是怎么回事? 码: 问题答案: 最好将所有swf都视为z阶无穷大。Flash是最重要的,只有很少的事情可以阻止它。另一方面,如果您可以访问SWF本身的代码,或者可以使用另一个SWF加载当前的SWF,则可以使用几个不同的Flash命令来处理页面的Jav