js之常见问题--for循环中为什么点击总是弹出最后一个i

首先看看点击不同li标签时,弹出li的索引值对应的结果

HTML:

<ul>
  <li>0</li>
  <li>2</li>
  <li>2</li>
  <li>3</li>
</ul>

JS:

for(var i = 0; i < aLi.length; i++){
  aLi[i].onclick = function(){
    alert(i);
  }
}

运行结果不尽人意,发现点击li后都是返回4,我们分析一下代码,

当i = 0时,aLi[0].onclick = function(){alert(i)}

当i = 1时,aLi[1].onclick = function(){alert(i)}

当i = 2时,aLi[1].onclick = function(){alert(i)}

当i = 3时,aLi[1].onclick = function(){alert(i)}

当i = 4时,不满足条件跳出循环

在执行click的函数的时候,会有一个作用域链,这个作用域链是一个对象列表,这组对象定义了代码作用域中的变量。( 可以详细了解一下变量对象的内容)当我们alert(i)的时候,会去从内到外的去寻找变量i。这个时候这个函数的作用域链上有4个对象,这时循环已经结束了,i此时的值为4.所以点击任何一个li,弹出的都是4,而不是我们想要的索引值。

那么问题来了,我们为了解决这个问题我们需要做的是每次给aLi[i]绑定事件的时候,将这个时候i的值保存在内部的作用域中

方法一:使用闭包的形式

for(var i= 0;i<aLi.length;i++){
  (function(i){
    aLi[i].onclick=function(){
      alert(i)
    }
  })(i)
}

这里涉及到一个块级作用域的概念。在es6出来之前,函数是作为创建块级作用域的主要手段。这里我们通过在aLi[i].onclick外面套上一层函数,将i作为参数,然后重新分析一下结果。

i = 0时,
(function(i){
aLi[0].onclick = function(){
alert(i);
}
})(0)
i = 1时,
(function(i){
aLi[1].onclick = function(){
alert(i);
}
})(1)
(function(i){
aLi[2].onclick = function(){
alert(i);
}
})(2)
(function(i){
aLi[3].onclick = function(){
alert(i);
}
})(4)
i = 4时,不满足条件跳出循环.

由于多了一层自执行函数的包裹,当我们点击li时,会有三层的作用域,从内带外分别是:click函数内部的变量对象,自执行函数的变量对象和最外层的window对象。查找到第二层的时候,找到了i,自执行函数的i等于传入的参数值,相对应的存下了当时i的值,所以就弹出了相应的索引值

方法二:使用ES6中的新特性let来声明变量

for(let i=0;i<aLi.length;i++){
aLi[i].onclick = function(){
alert(i)
}
}

方法三:引入jquery,使用其中的on或delegate进行事件绑定(它们都有事件代理的特性)

$("ul").on("click", "li", function(){
var index = $(this).index();
var info = $(this).html();
alert(index + "----" + info);
});

$("ul").delegate( "li", "click",function(){
var index = $(this).index(); //索引位置
var info = $(this).html();
alert(index + "----" + info);
});

posted @ 2020-11-12 12:08  smil、梵音  阅读(636)  评论(0编辑  收藏  举报