zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    js中取整数的方法
    js中原型和原型链
    js中获取class封装
    Cocos2dx打包成apk包时在手机上闪退
    计算两个日期间相差的天数
    Stealing a Cake [函数方程符合凸性 三分]
    插件式架构设计(转)
    转:Entity FrameWork利用Database.SqlQuery<T>执行存储过程并返回参数
    后台web请求代码(含https,json提交)
    sitecore 缓存管理器
  • 原文地址:https://www.cnblogs.com/first-time/p/6603036.html
Copyright © 2011-2022 走看看