闭包、定时器

问答

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

  • 闭包
    闭包就是能够读取其他函数内部变量的函数。在JavaScript中,只有函数内部的子函数才能够读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数。”
    比如在函数内部读取它的内部变量:
function f1(){
       var n = 999;
       function f2(){
              console.log(n);
       }
       return f2;
}
var result = f1();
resulet(); //999

上段代码中,函数f2就是闭包。

  • 作用
    1.可以读取函数内部的变量。
    2.让这些变量始终保存在内存中。
    举例来看闭包的作用:
function f1(){
       var n = 999;
       nAdd = function(){n+=1}
       function f2(){
       console.log(n);
       }
        return f2;
}
var result = f1();
result();//999
nAdd();
result();//1000

这段代码中,函数f2就是闭包,它一共运行了2次,第一次是999,第二次是1000,这说明了函数f1的局部变量n一直保存在内存中,并没有在f1调用后清除。

原因是f2被赋给了一个全局变量result,导致f2一直存在内存中,而f2的存在依赖于f1,所以f1也始终在内存中。

2. setTimeout 0有什么作用

setTimeout函数用来指定某个函数或某段代码在多少毫秒之后执行,它接受两个参数,要执行的代码和以毫秒表示的时间。
举例:

setTimeout(function() {
       console.log("jirengu")
},1000);//返回1,一秒钟后打印出jirengu

返回的整数表示这个定时器的编号,以后可以用来取消这个定时器,但实际任务中,很少这么用。

setTimeout函数的重点是第二个参数,第二个参数是一个表示等待多长时间的毫秒数,但是经过该时间的后执行的代码不一定会执行。

在理解这句话之前先说说JavaScript的运行机制:
JavaScript是一个单线程的解释器,一定时间之内只能执行一段代码。
为了控制要执行的代码,就有一个JavaScript任务队列。这些任务会按照将它们添加到队列的顺序执行。
setTimeout()的第二个参数告诉JavaScript再过多长时间把当前任务添加到队列中。也就是说setTimeout()指定的任务肯定是最后一个添加到队列中的,这个指定的任务要等到前面的任务执行完了以后再执行。
所以setTimeout函数的第二个参数应该理解为等到前面的任务执行之后再经过指定的毫秒数后来执行当前的任务
举例来说明吧:

console.log(1)
setTimeout(function() {
       console.log(2)
},100);
var t1 = Date.now()
for(var i=0;i<10000;i++){
      console.log(3);
}
var t2 = Date.now()
console.log(t2-t1);
运行结果

从运行结果中看到,console.log(2)确实是最后运行,而且是等到完成for循环的后再运行的,而不是之前理解的100ms之后会立即运行。

那么最后解释setTimeout 0就比较容易了,指的是setTimeout指定的任务在现有的任务执行之后立即执行。

代码题

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

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

在for循环中,i的值并没有随着循环保存在函数中,所以关键在于如何保存i的值,所以有了以下闭包的方法:

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

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

2.使用闭包封装一个汽车对象,可以通过以下方式获取汽车状态

var Car = //todo;
Car.setSpeed(30);
Car.getSpeed(); //30
Car.accelerate();
Car.getSpeed(); //40;
Car.decelerate();
Car.decelerate();
Car.getSpeed(); //20
Car.getStatus(); // 'running';
Car.decelerate(); 
Car.decelerate();
Car.getStatus();  //'stop';
//Car.speed;  //error

实现代码:

    var Car = (function(){
        var speed = 0;
        function setSpeed(){
            speed = arguments[0];
        }
        function getSpeed(){
            console.log(speed);
            return speed;
        }
        function accelerate(){
            speed += 10;
        }
        function decelerate(){
            speed -= 10;
        }
        function getStatus(){
            if(speed > 0){
                console.log("running");
                return "running";
            }else {
                console.log("stop");
                return "stop";
            }
        }
        return {
            "setSpeed":setSpeed,
            "getSpeed":getSpeed,
            "accelerate":accelerate,
            "decelerate":decelerate,
            "getStatus":getStatus
        }
    })()
    Car.setSpeed(30);
    Car.getSpeed(); //30
    Car.accelerate();
    Car.getSpeed(); //40;
    Car.decelerate();
    Car.decelerate();
    Car.getSpeed(); //20
    Car.getStatus(); // 'running';
    Car.decelerate();
    Car.decelerate();
    Car.getStatus();  //'stop';
运行结果

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

//方法一
    function interval(func,time){
        var intv = function(){
            func.call(null);
            setTimeout(intv,time);
        }
        setTimeout(interval,time);
    }

    interval(function(){
        console.log(1);
    },1000);


//方法二
    function interval(func, time){
        setTimeout(function(){
            func.call(null);
            interval(func,time);
        },time)
    }

    interval(function(){
        console.log(1);
    },1000)

需要注意的是,使用setTimeout并不能完全模拟出setInterval的功能。
在问答1中介绍过,setTimeout是等前面的任务执行之后再开始计算时间间隔。
而setInterval函数指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间,比如,setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。

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

    function getMini() {
        var i = 0;
        var start = Date.now();
        var clock = setTimeout(function(){
            i++;
            if(i === 1000){
                clearTimeout(clocl);
                var stop = Date.now();
                console.log((stop-start/1000));
            }
            else{
                var clock = setTimeout(arguments.callee,0);
            }
        },0)
    }
    getMini();

5.下面这段代码输出结果是?为什么?

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

由于setTimeout函数会把指定的任务放在最后执行,所以以上代码实际执行顺序如下:

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

所以最后的输出结果为1,3,2.

6.下面这段代码输出结果是?为什么?

var flag = true;
setTimeout(function(){
    flag = false;
},0)
while(flag){}
console.log(flag);

while方法会无限循环,无任何输出。
同上题,setTimeout函数会把指定的任务放在最后执行,所以实际执行顺序如下:

var flag = true;
while(flag){}
console.log(flag);
setTimeout(function(){
    flag = false;
},0)

变量flag一直为true,所以while方法会无限循环。

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

for(var i=0;i<5;i++){
    setTimeout(function(){
         console.log('delayer:' + i );
    }, 0);
    console.log(i);
}

实现代码:

//方法一
    for(var i=0; i<5; i++){
        (function(n){
            setTimeout(function(){
                console.log("delayer:" + n);
            },0)
        })(i);
        console.log(i);
    }
//方法二
     for(var i=0; i<5; i++){
         setTimeout((function(n){
             return function(){
                 return console.log("delayer:" + n);
             }
         })(i),0)
         console.log(i);
     }
运行结果

本文版权归本人和饥人谷所有,转载请注明来源。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • 问题 一、什么是闭包? 有什么作用? 1.什么是闭包①JavaScript高级程序设计第三版定义闭包是指有权访问另...
    鸿鹄飞天阅读 432评论 0 0
  • 一、什么是闭包?有什么作用 什么是闭包闭包是定义在一个函数内部的函数,它可以访问父级函数的内部变量。当一个闭包被创...
    __Qiao阅读 634评论 0 0
  • 问题 1.什么是闭包? 有什么作用 JavaScript高级程序设计第三版定义闭包是指有权访问另一个函数作用域中的...
    Lily的夏天阅读 385评论 0 0
  • 1.什么是闭包? 有什么作用 定义:闭包就是嵌套在函数里面的内部函数,并且该内部函数可以访问外部函数中声明的所有局...
    饥人谷区子铭阅读 851评论 0 2
  • 问题 一、什么是闭包? 有什么作用? 闭包闭包就是能够读取其他函数内部变量的函数。在javascript中,只有函...
    婷楼沐熙阅读 561评论 0 0