美文网首页
闭包和定时器

闭包和定时器

作者: sunny519111 | 来源:发表于2017-01-18 22:38 被阅读53次

    setTimeout的语法

    更新于2017年4月9号

    setTimeout(func,time,params)  //一定time后,传入回调函数的参数params,并调用回调函数
    setTimeout(func,time)  // 一定time后调用回调函数
    setTimeout(code,time) //一定time后调用代码块(不推荐)
    

    问题

    1.什么是闭包?有什么作用

    闭包:一个变量,一个函数(环境),函数内部可以访问到这个变量就是一个闭包。
    闭包的作用:1.可以访问函数内部的变量。2. 使变量可以一直保存在内存中。

    2.setTimeout 0有什么作用

    由于js的渲染机制是单线程序,无法同时执行多个不同的代码,当一个代码正在执行的时候,其他的代码都需要等待,直到正在运行的代码运行完后,才能运行下个等待的代码。所以一次点击事件,setTimeout,ajax异步请求都不是立刻的执行,而是立刻的排队。一旦线层空闲下来,就立刻执行。所以setTimeout 0不会立刻执行,而是排队等已经在执行的执行完,然后执行。

    var c= 0 ;
    function play(){
      console.log(c)
    }
    function add(){
      setTimeout(()=>{c+=1},100)
    }
    
    add()
    play()
    // 输出0
    
    console.log(1)
    setTimeout(function(){console.log},0)
    console.log(3)
    
    执行顺序
    console.log('start')
    setTimeout(function (){console.log("hello,200ms")},200)
    setTimeout(function (){console.log("hello,100ms")},100)
    console.log('end')
    //start
    //end
    //hello,100ms
    //hello,200ms
    
    console.log('start')
    setTimeout(function (){console.log("hello,200ms")},200)
    for(var i=0;i<10000;i++){console.log(1)}
    setTimeout(function (){console.log("hello,100ms")},100)
    console.log('end')
    //start
    //10000个1
    //end
    //hello,200ms
    //hello,100ms
    

    setTimeout会被异步到另一个内存中,当程序流执行完成后,如果时间程序流运行完,setTimeout的时间还没有到,就谁最短谁就呈现然后再执行setTimeout的程序。

    代码题

    1.下面的代码输出多少?修改代码让fnArr[i]() 输出 i。使用两种以上的方法

        var fnArr = [];
        for (var i = 0; i < 10; i ++) {
            fnArr[i] =  function(){
                return i;
            };
        }
        console.log( fnArr[3]() );  //10
    

    修改后

    1. 通过闭包来实现获取i
        var fnArr=[];
        for(var i=0;i<10;i++){
            fnArr[i]=function (n){
                var num =n;
                return function () {
                    return num;
                }
            }(i)}
            console.log(fnArr[5]())
    

    2.得不到i,无非就是你手速慢了,当你运行函数的时候,i的值就已经等于10了, 通过立即执行函数来获取i

        //第二种方法
        var fnArr=[];
        for(var i=0;i<10;i++){
            fnArr[i]=(function(){
                var obj ={};
                obj.i=i;
                return  obj.i
            })()
        }
    
    
        var fnArr=[];
        for(var i=0;i<10;i++) {
            (function(n){
                var num= n;
                fnArr[n] = function(){
                    return num;
                }
            })(i)
        }
    

    2. 使用闭包封装一个汽车对象

        var Car = (function () {
            var obj = new Object();
            obj.speed=0;
            obj.setSpeed=function (s) {
               obj.speed=obj.speed+s;
               return;
            }
            obj.getSpeed=function () {
                return obj.setSpeed;
            }
            obj.accelerate=function () {
               obj.speed=obj.speed+10;
               return
            }
            obj.decelerate =function (){
                obj.speed=obj.speed-10;
            }
            obj.getStatus =function (){
                if(obj.speed===0){
                    return 'stop'
                }
                else{
                    return 'running'
                }
            }
            return obj;
        })()
    
    

    3.写一个函数使用setTimeout模拟setInterval的功能

        setTimeout(function sayHello(){
            console.log("hello");
            setTimeout(sayHello,1000);
        },1000)
    

    拓展

    具名函数,全局函数,局部函数的区别

    1. 具名函数 :setTimeout里面的函数就是具名函数,只能在setTimeout里面使用,如果在外部调用会报错。


      具名函数
    2. 全局函数:在任何的作用域都可以使用,就像window自带的方法和属性
    3. 局部函数:只能在其父元素的函数作用域中使用(闭包除外)
      局部函数

    4.写一个函数,计算setTimeout平均最小时间粒度

    让setTimeout执行1000次,然后我们除以执行的次数

        function  getMini2() {
            var now = Date.now();
            console.log(now);
            var i =0;
            var clock=setTimeout(function () {
               i++;
               if(i===1000){
                   clearTimeout(clock);
                   var fnow = Date.now();
                   console.log((fnow-now)/i);
               }
               setTimeout(arguments.callee,0);
            },0)
        }
    
    

    5.函数输出的内容

    var a = 1;
    setTimeout(function(){
        a = 2;
        console.log(a);
    }, 0);
    var a ;
    console.log(a);
    a = 3;
    console.log(a);
    //1,3,2
    

    知识点1.变量的声明前置。2.setTimeout的异步加载处理
    由于setTimeout,所以匿名函数中的内容会在程序加载完成的空闲时间去执行,所以会被放到最后一个console.log(a)后执行。

    6.输出结果分析

    var flag = true;
    setTimeout(function(){
        flag = false;
    },0)
    while(flag){}
    console.log(flag);
    //无限死循环,没有任何输出
    

    Javascript引擎(JS引擎)是单线程的,在某一个特定的时间内只能执行一个任务,并阻塞其他任务的执行,也就是说这些任务是串行的。我们可以通过异步处理方法,当主线程在执行的过程中,异步处理的代码会被交到另一个模块去执行,当满足它执行的条件后,会被推到任务执行队列,在主线程全部加载完成,空闲下来后,就会去检查任务队列,执行里面的代码。
    所以上面的setTimeout(function(){flag=false},0)会被最后执行,这样while就死循环了

    7.下面这段代码输出?如何输出delayer: 0, delayer:1...(使用闭包来实现)

    for(var i=0;i<5;i++){
        setTimeout(function(){
             console.log('delayer:' + i );
        }, 0);
        console.log(i);
    }
    //输出
    //0,1,2,3,4 delayer: 5(5次)
    

    分析

    setTimeout(function(){
             console.log('delayer:' + i );
        }, 0);
    

    上面一个代码块会在for(var i=0;i<5;i++),执行完后再执行,所以得到的i就是5

    使用闭包输出delayer:0

        for(var i=0;i<5;i++){
            //我们把i传递到函数中
            (function(n){
                //用一个参数来接受它,然后返回一个函数调用这个参数
                var m = n;
                return setTimeout(function(){
                    return console.log('delayer:' + m);
                },0)//通过setTimeout自动让它执行
            })(i)//立即执行它,得到几个函数
        }
    

    相关文章

      网友评论

          本文标题:闭包和定时器

          本文链接:https://www.haomeiwen.com/subject/qqgvbttx.html