无ID情况下,JavaScript如何识别点击的对应商品操作按钮?
原代码
function render(ourCart) { ourCart.forEach(function(item) { const renderCart = document.createElement('div'); renderCart.innerText = item.name + ' $' + item.price; cart.appendChild(renderCart); const addButton = document.createElement('button'); addButton.innerText = 'Add'; renderCart.appendChild(addButton); renderCart.onclick = function() { total = total + (+item.price); console.log(item.name); console.log(item.price); } }) }
问题描述
该函数负责渲染商品的名称、价格,并生成用于累加商品总价的“Add”按钮。经测试,点击苹果旁的按钮两次后,控制台输出的total值正确为3*2=6。但存在疑问:未给按钮设置ID等标识的情况下,JavaScript是如何识别我点击的是苹果旁的按钮而非鸡蛋旁的按钮的?forEach循环会遍历数组中的每个对象,两次执行绑定onclick事件的逻辑,是否是onclick函数存储了临时值?
解答
1. 事件绑定的对象区分机制
每次forEach循环执行时,都会创建一个全新的renderCart div元素,并且给这个独立的div元素绑定了专属的onclick事件处理函数。
浏览器的事件模型是基于元素绑定的:每个DOM元素都可以拥有自己的事件监听器,当你点击页面上的某个元素(或其子元素,比如这里的按钮会触发父div的点击事件,因为事件冒泡),浏览器会精准触发该元素上绑定的事件函数,而非其他元素的。这个过程不需要ID来标识,因为事件是直接绑定到具体元素实例上的。
2. 闭包保存了商品数据
forEach的回调函数(接收item的那个函数)每次执行时,都会形成一个独立的闭包环境。这个环境会保存当前循环迭代对应的item变量引用。
当你点击div触发onclick函数时,这个函数会访问它所在闭包中的item变量——也就是当前循环对应的那个商品对象(比如苹果的item),而非其他商品的。相当于每个onclick函数都“记住”了自己对应的商品数据,所以能正确累加对应商品的价格、输出对应名称。
简单总结:每个div有自己的事件函数,闭包帮每个事件函数记住了对应的商品信息,所以不需要ID也能精准处理点击。
内容的提问来源于stack exchange,提问作者Nafi

