zoukankan      html  css  js  c++  java
  • 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);
    });

  • 相关阅读:
    LeetCode: 389 Find the Difference(easy)
    LeetCode: 669 Trim a Binary Search Tree(easy)
    C++: 内联函数
    C++: STL迭代器及迭代器失效问题
    LeetCode: 371 Sum of Two Integers(easy)
    etcdctl命令
    Etcd介绍
    docker基础镜像打包
    docker常见问题总结
    更改容器内时区
  • 原文地址:https://www.cnblogs.com/baoshuyan66/p/9971251.html
Copyright © 2011-2022 走看看