for循环与事件的i传值问题5种解决方法

5次阅读

共计 1468 个字符,预计需要花费 4 分钟才能阅读完成。

希望可以实现点击哪个就打印出对应的顺序

<ul>
  <li> 第 0 个 </li>
  <li> 第 1 个 </li>
  <li> 第 2 个 </li>
  <li> 第 3 个 </li>
  <li> 第 4 个 </li>
</ul>

错误实现:

注意此处使用的 var i=0, var 是可以被重复定义的,最后执行了 i ++,根据垃圾回收机制,当点击事件发生的时候,i 已经变成 5 了,所以不管点击哪个 li,打印的都是 5

window.onload=()=>{const list = document.querySelectorAll('li')
  for (var i=0; i<list.length; i++){list[i].onclick = ()=>{console.log(i)
    }
  }
}

正确实现:

方法一:给每个 li 添加自定义属性

window.onload=()=>{const list = document.querySelectorAll('li')
  for (var i=0; i<list.length; i++){list[i].index = i
    list[i].onclick = function (){console.log(this.index)
    }
  }
}

方法二:自执行函数,并利用作用域的关系,定义函数把 i 传进来,并进行自动调用

for (var i=0; i<list.length; i++){// (function(i){}) 表示定义,i 表示形参;(i) 表示调用,i 表示实参
  (function(i){list[i].onclick = function(){console.log(i)
    }
  })(i)
}

方法三:ES6 中的 let,let 应用于块级作用域,块级作用域以大括号划分
let 不会被垃圾回收机制回收,var 为什么会被回收?因为 var 声明的变量会被覆盖,而 let 不能被覆盖,就会被存下来。

for (let i=0; i<list.length; i++){list[i].onclick = ()=>{console.log(i)
    }
}

方法四:利用 for 循环的方法:filter、forEach、map(注意全都是 ES5 的,不是 ES6 的)

// 注意此处有一个兼容性问题,li 是类数组,兼容性好的浏览器可以直接使用这三个方法,但是兼容性不好的不能直接用
// 为保证稳妥,最好转成真正的数组
const newArr = [].slice.call(list) // 或者 const newArr = Array.prototype.slice.call(list), [] 是 Array 的原型
console.log(list) // NodeList(5) [li, li, li, li, li]      NodeList 是 dom 中的一个对象
console.log(newArr) //  [li, li, li, li, li]       被转成了真正的数组
newArr.forEach((value,index)=>{value.onclick=function(){console.log(index)
  }
})
newArr.filter((value,index)=>{value.onclick=function(){console.log(index)
  }
})
newArr.map((value,index)=>{value.onclick=function(){console.log(index)
  }
})

方法五:ES6 中给 Array 的 from 方法

Array.from(list, function(value, index){value.onclick=function(){console.log(index)
  }
})

正文完
 0