2

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

<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)
  }
})

七王国
326 声望39 粉丝