• 浅谈js for循环输出i为同一值的问题


    问题再现

    ​ 最近开发中遇到一个问题,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5。

    <html>  
        <head>  
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
            <title>闭包演示</title> 
        </head>  
        <body>  
            <p>1</p>  
            <p>2</p>  
            <p>3</p>  
            <p>4</p>  
            <p>5</p> 
            <script type="text/javascript">
                window.onload=function() {  
                    var ps = document.getElementsByTagName("p");  
                    for( var i=0; i<ps.length; i++ ) {  
                        ps[i].onclick = function() {  
                            alert(i);  
                        }  
                    }  
                }  
            </script> 
        </body>  
    </html>
    

    此时点击任意p弹出的都是5

    出现原因:js事件处理器在线程空闲时间不会运行,导致最后运行的时候输出的都是i最后的值,即:5


    解决办法:使用闭包将变量i的值保护起来

    //sava1:加一层闭包,i以函数参数形式传递给内层函数 
    for( var i=0; i<ps.length; i++ ) {  
        (function(arg){   
            ps[i].onclick = function() {   
                alert(arg);  
            };  
        })(i);//调用时参数  
    } 
    
    
    //save2:加一层闭包,i以局部变量形式传递给内存函数 
    for( var i=0; i<ps.length; i++ ) {  
        (function () {  
            var temp = i;//调用时局部变量  
            ps[i].onclick = function() {  
                alert(temp);  
            }  
        })();  
    }
    
    
    //save3:加一层闭包,返回一个函数作为响应事件(注意与3的细微区别) 
    for( var i=0; i<ps.length; i++ ) {  
        ps[i].onclick = function(arg) {  
            return function() {//返回一个函数  
                alert(arg);  
            }  
        }(i);  
    } 
    
    
    //save4:将变量 i 保存给在每个段落对象(p)上  
    for( var i=0; i<ps.length; i++ ) {  
        ps[i].i = i;  
        ps[i].onclick = function() {  
            alert(this.i);  
        }  
    }
    
    
    //save5:将变量 i 保存在匿名函数自身  
    for( var i=0; i<ps.length; i++ ) {  
        (ps[i].onclick = function() {  
            alert(arguments.callee.i);  
        }).i = i;  
    }   
    } 
    
    
    //save6:用Function实现,实际上每产生一个函数实例就会产生一个闭包
    for( var i=0; i<ps.length; i++ ) {  
        ps[i].onclick = new Function("alert(" + i + ");");//new一次就产生一个函数实例 
    } 
    
    
    //save7:用Function实现,注意与6的区别  
    for( var i=0; i<ps.length; i++ ) {  
        ps[i].onclick = Function('alert('+i+')'); 
    }
    

    总结

    在ECMAScript5和6中,var和let的作用域是不同的:var的作用域在函数上,let的作用域在块上,因此当有异步函数发生调用的时候,之前已经绑定好的点击事件会寻找在onload函数的i值,此时i值已经不是当初设定好的值,而是最后一次循环后的值,而使用let的话,那么在每次循环的时候就会在新的块上重新创建新的变量i,所以每次点击的i的值都会不同。

  • 相关阅读:
    图片懒加载原生写法。
    ES6新声明
    下拉刷新上拉加载
    angular动画
    angular路由切换后 轮播以及iscrollJs失效的问题
    ui-route多级嵌套时的默认显示。
    iscroll.js的基本布局
    angular ng-route和ui-route
    require.js JQ
    Cookie&Session
  • 原文地址:https://www.cnblogs.com/eden-libinglin/p/13947804.html
Copyright © 2020-2023  润新知