• for循环绑定事件解决方法


      首先我们来看一段代码

    <body>
        <ul id="ul">
            <li>1111</li>
            <li>2222</li>
            <li>3333</li>
            <li>4444</li>
            <li>5555</li>
        </ul>
        
        <script type="text/javascript">
            var oUl = document.getElementById("ul");
            var aLi = oUl.getElementsByTagName("li");
            for(var i = 0; i < aLi.length; i++){  
                        aLi[i].onclick = function (){  
                            alert(i);  
                        };
                    }  
        </script>
    </body>

      运行之后发现无论点哪个标签,弹出的都是最后一个标签的index

      这是因为 for 循环的里面 var 定义的变量 i 自动提升为全局变量,等同于下面的代码

    <script type="text/javascript">
        var oUl = document.getElementById("ul");
        var aLi = oUl.getElementsByTagName("li");
        var i;
        for(i = 0; i < aLi.length; i++){  
            aLi[i].onclick = function (){  
                alert(i);  
            };
        }  
    </script>  

      这时候 alert(i) 里面的i还没有值,当用户调用 onclick 的匿名函数时,需要对i求值

      解析程序首先会在事件处理程序内部查找,但 i 没有定义。然后,又到方法外部去查找,此时有定义,但此时的i已经循环完毕,因此,无论点哪个标签,弹出的都是最后一个标签的index。

      有以下几种方法解决:

      立即调用的函数表达式(IIFE);不懂的可以看看我之前写的  点击这里

    <body>
        <ul id="ul">
            <li>1111</li>
            <li>2222</li>
            <li>3333</li>
            <li>4444</li>
            <li>5555</li>
        </ul>
        
        <script type="text/javascript">
            var oul = document.getElementById("ul");
            var ali = oul.getElementsByTagName("li");
            for(var i = 0; i < ali.length; i++){
                (function(i){   //这里的i类似形参 
                    ali[i].onclick = function (){  
                        alert(i);   
                    } 
                })(i);   //这里的i类似实参
             
        }  
        </script>
    </body>   

      将变量 i 保存给在每个段落对象(li)上

    <body>
        <ul id="ul">
            <li>1111</li>
            <li>2222</li>
            <li>3333</li>
            <li>4444</li>
            <li>5555</li>
        </ul>
        
        <script type="text/javascript">
            var oul = document.getElementById("ul");
            var ali = oul.getElementsByTagName("li");
            for(var i = 0; i < ali.length; i++){
                ali[i].i = i;
                    ali[i].onclick = function (){  
                        alert(this.i);   
                    } 
            }  
        </script>
    </body> 

      将变量 i 保存在匿名函数自身

    <body>
        <ul id="ul">
            <li>1111</li>
            <li>2222</li>
            <li>3333</li>
            <li>4444</li>
            <li>5555</li>
        </ul>
        
        <script type="text/javascript">
            var oul = document.getElementById("ul");
            var ali = oul.getElementsByTagName("li");
            for(var i = 0; i < ali.length; i++){
                (ali[i].onclick = function (){  
                    alert(arguments.callee.i);   
                }).i = i
            }
        </script>
    </body> 

      还有一种使用ES6新语法 let 关键字 由于是新语法 各浏览器支持不同

    <body>
        <ul id="ul">
            <li>1111</li>
            <li>2222</li>
            <li>3333</li>
            <li>4444</li>
            <li>5555</li>
        </ul>
        
        <script type="text/javascript">
            var oul = document.getElementById("ul");
            var ali = oul.getElementsByTagName("li");
            for(let i = 0; i < ali.length; i++){
                ali[i].onclick = function (){  
                    alert(i);   
                }
            }
        </script>
    </body>

      关于let,我一直似懂非懂,后来在阮一峰老师的《ECMAScript 6 入门》这本书上找到了答案

      使用let,声明的变量仅在块级作用域内有效,当前的 i 只在本轮循环有效,所以每次都是一个新的变量

      可能你会问,如果每一轮循环的变量 i 都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值

      这是因为Javascript引擎内部会记住上一轮循环的值,初始化本轮的变量 i 时,就在上一轮循环的基础上进行计算。

      题外话

      for循环还有一个特别之处,就是循环语句部分是一个父作用域,而循环体内部则是一个单独的子作用域

    for (let i = 0; i < 3; i++) {
        let i = "abc" ;
        console.log(i);
    }
     // abc
     // abc
     // abc

       上面的代码输出了3次 abc,这表明函数内部的变量 i 和外部的变量 i 是分离的

  • 相关阅读:
    Objective-C面向对象-对象和类
    eImage(仅两行代码实现输出从数据库中查询到的二进制字段)标签
    yii第三方插件snoopy配置
    iOS应用崩溃日志分析 iOS应用崩溃日志揭秘
    斯坦福《机器学习》Lesson6感想———1、函数间隔和几何间隔
    openstack 中国联盟公开课參会总结
    【翻译自mos文章】多租户中的service管理
    谷歌浏览器訪问不了啦,oh shit!
    从程序员转向淘宝店主的探索
    Python爬取韩寒所有新浪博客
  • 原文地址:https://www.cnblogs.com/zhang-xun/p/6770670.html
Copyright © 2020-2023  润新知