JavaScript中点击图片获取名称总返回最后一张的原因是什么
问题根本原因
这是JavaScript中var声明的作用域特性结合闭包导致的经典问题:
- for循环内你用
var声明了canvas_name、image_name、cell三个变量,var不存在块级作用域,这三个变量的作用域绑定在allImages函数整体,整个函数运行周期内只会存在一份对应的内存空间 - 每次循环都会覆盖这三个变量的存储值,你给canvas绑定的
onclick回调属于闭包,内部引用了这三个变量,但回调函数不会在绑定的时候立刻执行,只会在用户点击时才触发 - 等到用户点击触发回调时,for循环已经完全执行完毕,这三个变量已经被覆盖为最后一次循环(index=4)对应的值,因此无论点击哪张图片,输出的都是最后一张的信息
注意:你代码里的index因为用了let声明,本身是有块级作用域的,每个循环都有独立的index副本,问题出在另外三个用var声明的变量上
修复方案
方案1:替换变量声明关键字
最简单的修复方式是把循环内的var全部替换为let,let具备块级作用域,每次循环都会生成独立的变量副本,每个闭包引用的都是当前轮次对应的变量值,不会被后续循环覆盖:
function allImages() { for (let index = 0; index < 5; index++) { // 把var改成let let canvas_name = "display-" + index let image_name = 'image_' + index + '.png' drawImage(canvas_name, image_name) // 把var改成let let cell = document.getElementById('display-' + index) cell.onclick = function() { cellClick(index, image_name) }; } }
方案2:通过DOM自定义属性存储数据
你也可以把需要的参数直接绑定到DOM元素的自定义属性上,点击时从事件对象中读取对应属性值,完全规避闭包问题:
function allImages() { for (let index = 0; index < 5; index++) { var canvas_name = "display-" + index var image_name = 'image_' + index + '.png' drawImage(canvas_name, image_name) var cell = document.getElementById('display-' + index) // 绑定自定义属性 cell.dataset.index = index cell.dataset.imageName = image_name cell.onclick = function(e) { // 从事件目标的属性中读取值 cellClick(e.target.dataset.index, e.target.dataset.imageName) }; } }
内容的提问来源于stack exchange,提问作者Psionman
相关产品推荐
相关产品推荐

