• for 循环中的 i 变量取值问题


    1:如何点击某一个 li 的时候 alert 输出其index?

    <ul id="test">

      <li>111</li>

      <li>222</li>

      <li>333</li>

      <li>444</li>

    </ul>

    window.onload = function(){

      var oLis = document.getElementById("test").getElementsByTagName("li");

      for(var i = 0;i < oLis.length;i ++){

        oLis[i].onclick = function(){

          alert(i); //每次都是4

        }

      }

    }

    解析:因为在for循环里面指定给oLis[i].onclick的事件处理程序,也就是onclick那个匿名函数是在for循环执行完成后(用户点击时)才被调用的。而调用时,需要对变量i求值,解析程序首先会在事件处理程序内部查找,但i没有定义,然后又到方法外部查找,此时有定义,但i的值是4(只有i大于4才会停止执行for循环),因此,就会取到该值——这正是闭包(匿名函数)要使用其外部作用域中变量的结果。而且,这也是由于匿名函数本身无法传递参数(故而无法维护自己的作用域)造成的.(比较啰嗦,可以看下面的解释)

    其实是根据作用域链的原理,在这个函数里面的i其实引用的是最后一次i的值,为什么不是0,1,2,3,...呢?因为在你for循环的时候,你并没有执行这个函数,你这个函数是在你点击的时候才执行的,当执行这个函数的时候,它发现它自己没有这个变量i,于是向它的作用域链中查找这个变量i,因为当你单击这个box的时候已经for循环完了,所以储存在作用域链里面的i的值就是4,最后就弹出出来4了。


    2:解决办法:将每次for循环中的变量i保存到某个地方;

    方法一:

    window.onload = function(){

      var oLis = document.getElementById("test").getElementsByTagName("li");

      for(var i = 0;i < oLis.length;i ++){

        (function(i){

          oLis[i].onclick = function(){

            alert(i); //0123

          }

        })(i);

      }

    }

    解释:成功打印每个 i 的值,原理就是通过自执行函数,将变量i保存到这个自执行函数的参数中。

    方法二:

    window.onload = function(){

      var oLis = document.getElementById("test").getElementsByTagName("li");

      for(var i = 0;i < oLis.length;i ++){

        oLis[i].index = i;

        oLis[i].onclick = function(){

          alert(this.index); //0123

        }

      }

    }

    解释:将每次循环得到的i,赋值给oLis[i]对象的index属性,在通过this指向,取出点击当前对象的index的值。

    方法三:

    window.onload = function(){

      var oLis = document.getElementById("test").getElementsByTagName("li");

      for(var i = 0;i < oLis.length;i ++){

        oLis[i].onclick = (function(e){

          return function(){

            alert(e); //0123  

          }

        })(i);

      }

    }

    解释:


    3:解决办法:让这个函数直接执行;

    window.onload = function(){

      var oLis = document.getElementById("test").getElementsByTagName("li");

      for(var i = 0;i < oLis.length;i ++){

        oLis[i].onclick = a();

          function a(){

            alert(i); /0123

        }

      }

    }

    解释:虽然这样可以打印出每次变量i的值,但是我们没有点击li的时候他已经执行完了,也就是说,这个点击事件已经可有可无了,所以我们这种方法在绑定事件中不可用。


    4:ES6为我们新增了,定义变量的关键字 let

    window.onload = function(){

      var oLis = document.getElementById("test").getElementsByTagName("li");

      for(let i = 0;i < oLis.length;i ++){

        oLis[i].onclick = function(){

          alert(i); //0123

        }

      }

    }

    解释:let允许声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,它声明的变量只能是全局或者整个函数块的。

    let的几点用法:

    1>用于声明变量,不做变量提升;

    2>在同一个作用域中,不允许重复声明同一个变量;

    3>会产生块级作用域{ };

    4>特殊注意:for循环是一个块级作用域,for后{}是一个块级作用域,for块级作用域是for{}块级作用域的父级作用域。

    for(let i = 0;i < 5;i++,console.log( i )){ 0 1 2 3 4

      let i = 10;console.log( i );    10 10 10 10 10

    }

    alert(i);//报错

    循环执行了几次,就存几个块级作用域,每一个块级作用域都有一个变量 i ,但是这几个i不是同一个i 。(函数内部的变量i 与 循环变量i 不在同一个作用域,有各自单独的作用域)

  • 相关阅读:
    Oracle GoldenGate部署系列
    SequoiaDB培训视频
    Macbook 修复Office Excel 异常问题
    linux vim 配置 go 开发环境
    hyperledger fabric 1.0.5 分布式部署 (九)
    IntelliJ IDEA 安装golang 插件
    hyperledger fabric 1.0.5 分布式部署 (八)
    docker 学习
    spring-boot 集成ehcache报错:org.springframework.expression.spel.SpelEvaluationException: EL1008E:
    CentOS7 Docker 安装
  • 原文地址:https://www.cnblogs.com/lisaShare/p/8478614.html
Copyright © 2020-2023  润新知