循环内绑定DOM元素事件时,所有事件触发输出相同key的问题求助
解决循环中绑定事件时变量引用统一的问题
这个问题是JavaScript里非常经典的函数作用域陷阱,我来帮你理清楚原因和解决办法:
问题根源
你在循环里用了var key来声明变量,但var是函数作用域(或者全局作用域)的变量——也就是说整个循环里其实只有一个key变量,每次循环只是更新它的值。当点击事件触发时,循环早就执行完了,key已经被赋值为循环的最后一个属性名,所以所有点击事件里的console.log(key)都会打印同一个结果。
三种解决方案
方案1:用let代替var(最简洁)
let是ES6引入的块级作用域变量,每次循环都会创建一个全新的key变量,每个点击事件都会捕获当前循环迭代的那个key值:
var dom = {}; var popupContent = L.DomUtil.create('div'); // 把var替换成let for(let key in this._info){ dom[key] = L.DomUtil.create('a', "", popupContent); dom[key].innerHTML = key; dom[key].href = "#"; L.DomEvent.on(dom[key], 'click', function(){ // do some stuff console.log(key); }); } var popup = L.popup(); popup.setLatLng(latlng) .setContent(popupContent) .openOn(this._map);
方案2:用闭包保存当前变量值(兼容旧环境)
如果需要兼容不支持ES6的环境,可以用立即执行函数表达式(IIFE)创建独立作用域,把当前循环的key值传递进去:
var dom = {}; var popupContent = L.DomUtil.create('div'); for(var key in this._info){ dom[key] = L.DomUtil.create('a', "", popupContent); dom[key].innerHTML = key; dom[key].href = "#"; // 用IIFE包裹,传入当前key作为参数 (function(currentKey) { L.DomEvent.on(dom[key], 'click', function(){ // do some stuff console.log(currentKey); }); })(key); } var popup = L.popup(); popup.setLatLng(latlng) .setContent(popupContent) .openOn(this._map);
方案3:用forEach遍历(更现代的写法)
可以把for...in换成Object.entries配合forEach,forEach的每个回调函数都有独立的作用域,能自然保存当前的key值:
var dom = {}; var popupContent = L.DomUtil.create('div'); // 遍历对象的键值对 Object.entries(this._info).forEach(([key]) => { dom[key] = L.DomUtil.create('a', "", popupContent); dom[key].innerHTML = key; dom[key].href = "#"; L.DomEvent.on(dom[key], 'click', function(){ // do some stuff console.log(key); }); }); var popup = L.popup(); popup.setLatLng(latlng) .setContent(popupContent) .openOn(this._map);
总结
推荐优先使用方案1(let)或者方案3(forEach),代码更简洁易读,也符合现代JavaScript的写法。
内容的提问来源于stack exchange,提问作者mohammad fatemi
相关产品推荐
相关产品推荐

