ReactJS点击事件传参异常:点击所有Li均传递数组最后元素值
为什么点击所有li都触发数组最后一个元素的参数?
嘿,这个问题我踩过好多次了——这是闭包的作用域陷阱在搞怪!
问题根源
大概率你是用var声明的循环变量(比如var i或者var item),然后在循环里给每个li绑定onclick事件。var的作用域是函数级的,不是块级的,所以所有的onclick事件处理函数都会共享同一个变量引用。
举个典型的错误代码例子:
var arr = ['a', 'b', 'c']; for (var i = 0; i < arr.length; i++) { var li = document.createElement('li'); li.textContent = arr[i]; li.onclick = function() { console.log(arr[i]); // 不管点哪个,最后都输出数组最后一个元素(甚至可能是undefined) }; document.body.appendChild(li); }
循环跑完后,变量i已经变成了循环终止的那个值(比如数组长度3),当你点击任何li时,事件函数才会去读取i的当前值,自然就拿到了最后一个元素的索引(或者超出索引的undefined)。说白了,所有事件函数都“记住”的是同一个变量的引用,而不是循环时那个变量的当前值。
解决办法
给你几个常用的方案,按需选择:
1. 用let代替var(最推荐,ES6+)
let是块级作用域,每次循环迭代都会创建一个新的变量绑定,每个事件函数捕获的都是当前迭代的专属变量:
const arr = ['a', 'b', 'c']; for (let i = 0; i < arr.length; i++) { const li = document.createElement('li'); li.textContent = arr[i]; li.onclick = () => { console.log(arr[i]); // 点哪个就输出哪个对应的元素 }; document.body.appendChild(li); }
2. 立即执行函数(IIFE,兼容老环境)
如果项目还不能用ES6,用IIFE给每个迭代创建独立作用域,把当前值封进去:
var arr = ['a', 'b', 'c']; for (var i = 0; i < arr.length; i++) { var li = document.createElement('li'); li.textContent = arr[i]; // 用IIFE把当前的arr[i]存到独立作用域里 li.onclick = (function(currentItem) { return function() { console.log(currentItem); }; })(arr[i]); document.body.appendChild(li); }
3. 用forEach循环
forEach的回调函数本身会创建新作用域,每个迭代的item都是独立的:
const arr = ['a', 'b', 'c']; arr.forEach(item => { const li = document.createElement('li'); li.textContent = item; li.onclick = () => { console.log(item); }; document.body.appendChild(li); });
4. 用bind绑定参数
直接把当前元素作为参数绑定到事件函数上:
var arr = ['a', 'b', 'c']; for (var i = 0; i < arr.length; i++) { var li = document.createElement('li'); li.textContent = arr[i]; li.onclick = function(item) { console.log(item); }.bind(null, arr[i]); document.body.appendChild(li); }
核心逻辑都是:让每个事件处理函数拿到的是当前迭代的变量副本,而不是共享同一个变量引用。
内容的提问来源于stack exchange,提问作者zozo
相关产品推荐
相关产品推荐

