• 其实函数引用的外部变量都是最后一次的值。


     

    其实函数引用的外部变量都是最后一次的值。

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style>
            #box{
                100px;
                height:100px;
                background-color:pink;
            }
        </style>
        <script src="index.js"></script>
    </head>
    <body>
        <div id="box"></div>
    </body>
    </html>
    ///////////////////////////////js代码//////////////////////////
    window.onload = function(){
        var box = document.getElementById("box");
        var num = 0;
        function a(){
            console.log(num);
        }
    
        box.onclick = function(){
            num ++;
            a(); // 1,2,3,4....每次单击都会加1,说明函数引用外部变量是引用那个变量的最后一次的值。
        }
    }
    复制代码

    再来看一个例子:

    复制代码
    window.onload = function(){
        var box = document.getElementById("box");
        var num = 0;
        for(var i=0;i<10;i++){
            box.onclick = function(){
                console.log(i); //总是打印10
            }
        }
        
    }
    复制代码

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

    for(var i=0;i<10;i++){
        function a(){
            console.log(i);
        }
        a(); //1,2,3,4,5....
    }

    为什么这样就可以呢?因为你在循环变量i的时候已经执行了函数a,自然变量i是什么就打印出来什么。

    现在知道为什么绑定事件的时候打印出来的是最后一次的for循环的值了吧。

    如果你知道理解这段话,我相信你知道怎么去解决这个问题。

      解决方法1:让这个函数直接执行。

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

    方法1:

    复制代码
    window.onload = function(){
        var box = document.getElementById("box");
        var num = 0;
        for(var i=0;i<10;i++){
            box.onclick = a();
            function a(){
                console.log(i); //1,2,3,4.....
            }
        }
        
    }
    复制代码

      虽然这样可以打印出每次的变量i的值,但是我们没有点击box的时候它已经执行完了,直接无视了点击事件,也就是说这个点击事件已经可有可无了,所以我们用这种方法在绑定事件中就显得不那么可用了,那我们用方法2试试吧。

    方法2:

    复制代码
    window.onload = function(){
        var div = document.getElementsByTagName("div");
        var num = 0;
        for(var i=0;i<div.length;i++){
            (function(i){
                div[i].onclick = function(){
                    console.log(i); 
                }
            })(i)
        }
        
    }
    复制代码

      成功打印每个i的值,原理就是通过自执行函数,并且将变量i保存到这个自执行函数的参数中。如果你不知道什么是自执行函数可以看初识js中的闭包这一节。

    你们我们应该选择那种方法呢?当然看你的情况了,如果没有关于绑定事件的话,就是说让这个函数直接执行的,那就用方法1,否则用方法2,另外方法2通用,但是因为里面的i会一直保存到内存中比较消耗性能的原因,所以在没有必要的情况下尽量不要用这种方式,其实还可以将i绑定到元素的属性上。

  • 相关阅读:
    [图形学] 结束 [Unity Shader] 开始
    [图形学] Chp18 OpenGL表面纹理函数
    [图形学] Chp17 OpenGL光照和表面绘制函数
    [图形学] Chp14 GLU曲面裁剪函数程序示例及样条表示遗留问题
    [图形学] Chp10 OpenGL三维观察程序示例
    [图形学] 问题: 裁剪窗口坐标对应显示窗口中像素是一对一还是一对多?
    [图形学] Chp9 三维几何变换--栈处理函数与矩阵管理函数的区别
    [图形学] 习题8.12 NLN二维线段裁剪算法实现
    [图形学] 习题8.6 线段旋转后使用Cohen-Sutherland算法裁剪
    [图形学] Chp8 使用双缓存创建帧动画
  • 原文地址:https://www.cnblogs.com/zhangxiaolei521/p/5217901.html
Copyright © 2020-2023  润新知