• JavaScript---循环与闭包


      循环与闭包

        先看一个demo

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            for(var i = 0; i <= 5; i++){
                
                    setTimeout(function timer(){
                        console.log(i);
                    }, i*1000);
                    
            }
    
        </script>
    </body>
    </html>

        结果会打印出什么? 相信大家都知道 答案是 6个6; 我们本意是打印出:0,1,2,3,4,5  但结果却是6个6, 为什么?首先解释一下为什么打印出6:这里涉及到延时函数的执行机制,虽然延时函数表明是i秒后执行,而i秒是相对与所有可执行代码执行完那一刻开始计时的,也就是等for循环结束之后,延时函数才开始执行。但此时 i= 6;所以会打印出6. 现在在解释一下为什么是6个6:很简单,for循环每执行一次就创建出一个延时函数,执行了6次,就会有6个延时函数。这6个延时函数共享一个作用域(本例中全局作用域) i又累加到6,所以会打印出6个6!!

        分析完整个过程,你知道问题出现在哪里吗?   有2个问题  1:每执行一次for循环,应该执行一次延时函数,但并没有。2:所有的延时函数共享一个作用域。

    知道问题的地方,那就很好解决了:每循环一次,创建一个作用域 。 关键是如何实现“每循环一次,创建一个作用域”, 其实很简单,每循环一次,就立即执行一次延时函数,立即执行函数(IIFE)就派上用场了 它的原理很“粗暴”:每个延时函数都会将IIFE在每次迭代中创建的作用域 封闭起来。ok,修改一下我们的代码:

      

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            for(var i = 0; i <= 5; i++){
                (function(){
                    setTimeout(function timer(){
                        console.log(i);
                    }, i*1000);
                })();
                    
            }
    
        </script>
    </body>
    </html>

      在chrome中显示:

      咦??? 怎么还是6个6!!!  问题出在哪里?  其实很简单,仔细看一下,我们的IIFE只是一个什么都没有的空作用域(i是全局变量,处于全局作用域中) 它需要有自己的变量,用来在每个迭代中存储i的值   再来改进一下代码:

      

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            for(var i = 0; i <= 5; i++){
                (function(){
                    var j = i;
                    setTimeout(function timer(){
                        console.log(j);
                    }, j*1000);
                })();
                    
            }
    
        </script>
    </body>
    </html>

      在chrome中显示:

      把i值存进来,就可以实现 我们的预期了。到现在为止,代码已经是没有错误的了。但是,还可以优化:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            for(var i = 0; i <= 5; i++){
                (function(i){
                    setTimeout(function timer(){
                        console.log(i);
                    }, i*1000);
                    
                })(i)
            }
    
    
    
        </script>
    </body>
    </html>

      把i当作参数传进去,我们的代码就更完美了。

                                            2017-3-23  0:19

  • 相关阅读:
    基于HT for Web矢量实现3D叶轮旋转
    基于HT for Web矢量实现2D叶轮旋转
    HT for Web列表和3D拓扑组件的拖拽应用
    基于HT for Web矢量实现HTML5文件上传进度条
    Java 8 VM GC Tunning Guide Charter 5
    Java 8 VM GC Tunning Guide Charter 6
    Java 8 VM GC Tunning Guide Charter 7-8-b
    Java 8 VM GC Tunning Guild Charter 9-b
    java文档 第十一章 其他考量-b
    iOS点击cell查看大图,点击大图还原小图-b
  • 原文地址:https://www.cnblogs.com/first-time/p/6603036.html
Copyright © 2020-2023  润新知