闭包、定时器

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

  • 定义:闭包就是嵌套在函数里面的内部函数,并且该内部函数可以访问外部函数中声明的所有局部变量,参数和其他内部的函数。当该内部函数在外部函数外被调用了,就生成了闭包。
(1)闭包包括了函数和创建该函数的环境。这个环境由闭包创建时在作用域中的任何局部变量组成。
(2)[函数]和[函数内部能访问到的变量(也叫环境)]的总和,就是一个闭包。
(3)闭包不是非得return回一个函数,return出一个对象也可以是闭包。
(4)特点一:作为一个函数变量的一个引用,当函数返回时,其处于激活的状态。
(5)特点二:一个闭包就是当一个函数返回的时候,一个没有释放资源的栈区。
  • 作用:
    (1)保存变量现场,封装私有变量
    (2)隔离作用域;
    (3)做计时器
    (4)独立了一个命名空间
    (5)闭包会使变量驻留内存,不会被自动清除;使用时应谨慎,以免引起内存泄露,影响性能
闭包的缺点:
1.在IE9之前因为使用不同的垃圾收集机制会导致循环引用会造成内存泄漏
2. 闭包会携带包含函数的作用域,所以会比其他函数占用更多内存,过度使用闭包会造成内存占用过多
例子:
在函数内部读取它的内部变量:
function fn(){
    var a = 1;
    function add(){
      a+=1
      console.log(a)
    }
    return add //add就是一个桥梁
}
var r = fn() //闭包,包括函数add和包含变量a的环境
r() //输出2  
//add被赋给了一个全局变量r,导致add一直存在内存中,而add的存在依赖于a,所以a也始终在内存中。
因此:闭包就是一个桥梁,连接着外部环境和父函数的局部变量
经典例子:
(function(){
   var arr = []
   for(var i=0;i<5;i++){
        arr[i] = function(){
          console.log(i)
        }
  }
  arr[1]()
})()
为什么!!!无论arr[1]-arr[5]()输出结果都是5,因为所访问的i是外部函数的,
当循环完以后,i已经累加到5了,所以无论多少输出当然是5(作用域链)

利用闭包特点可以保存变量现场(让变量不被释放):
(function() { 
    var arr = [] 
    for (var i = 0; i < 5; i++) { 
          arr[i] = function (n) { 
            return function () { 
                      alert(n) 
            } 
          }(i) //把i传递进来,作用域中就可以取到当前的i
     } 
     arr[1]()//输出当前值1
})()

2.setTimeout 0 有什么作用

  • 定义:setTimeout函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。

(1)setTimeout(func|code, delay),一般接受两个参数,第一个参数可以是字符串,也可以是func函数名,第二个参数是设置多少毫秒ms后执行代码.如果省略第二个参数,该参数默认为0.
(2)setTimeout(“code”,millisec):执行代码必须用字符串形式,millise设置在多少毫秒之后执行这段代码。
eg:setTimeout('console.log(2)',1000); //1000ms后控制台输出2
(3)setTimeout(fn,millisec)中fn为函数名,也可以是回调函数,但记得是写函数名而不是写调用函数,millise设置在多少毫秒之后执行这个函数。
(4)可以把setTimeout中的函数排在任务队列末尾,等待其他语句全部执行完毕再开始立即执行,可以理解为setTimeout优先级在任务队列中最低

setTimeout (‘console.log(最尾)',0)//代表当前任务队列执行后才立刻执行输出“最尾”
setTimeout('console.log(最尾了但还要1000ms后再执行)',1000)//代表当前任务队列执行后再过1000ms才执行
例子:
setTimeout('console.log(1)',1000); //右边为执行顺序:  2
console.log(2); //                                  3
console.log(3); //                                  4
setTimeout('console.log(4)',0);//                   1

总结:setTimeout 0 有什么作用?(任务队列中优先级最低)
可以让setTimeout中的函数排在任务队列末尾,等待其他语句全部执行完毕再开始立即执行


3.下面的代码输出多少?修改代码让fnArr1输出 i。使用两种以上的方法

题目:
var fnArr = []; 
for (var i = 0; i < 10; i ++) { 
        fnArr[i] = function(){ 
            return i; 
      }; 
} 
console.log( fnArr[3]() );~~~无奈都是输出10,因为执行函数之前 i=10;在for循环中,
i的值并没有随着循环保存在函数中,所以关键在于如何保存i的值,所以有了以下闭包的方法:
——————————————————————————————————————————————————————
//使用闭包函数实现返回当前传入的值
方法一:
var fnArr = []; 
for(var i = 0;i < 10;i++) { 
     fnArr[i] = function(n){//用数组记录下循环中每次的值
         return function(){
           return n;
         }
     }(i) //每次循环传入实参i
} 
console.log( fnArr[3]() );//输出3
————————————————————————————————————————————————————
方法二:
function func(val) { 
    return function() { 
          return val;
       }; 
  } 
var fnArr = []; 
for (var i = 0; i < 10; i++) {
 //将返回值(i)存入fnArr数组 
      fnArr[i] = func(i); 
} 
console.log(fnArr[3]());//输出3
——————————————————————————————————————————————————————
方法三:
var fnArr = []; 
for(var i=0;i<10;i++){
  (function(n){
    fnArr[n] = function(){
      return n
    }
  })(i)//将i作为实参传入立即执行函数
}
console.log( fnArr[3]());//输出3

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

解答:
var Car = (function(){
    var val;
    function setSpeed(val){
      speed = val;
    }
    function getSpeed(){
      return speed;
    }
    function accelerate(){
      speed +=10;
    }
    function decelerate(){
      speed -=10;
    }
    function getStatus(){
      if(speed===0){
        return "stop";
      }else{
        return "running";
      }
    }
    return {
      "setSpeed":setSpeed,
      "getSpeed":getSpeed,
      "accelerate":accelerate,
      "decelerate":decelerate,
      "getStatus":getStatus
    };
}());

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

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

方法一:
var i = 0;
function fn(){
    setTimeout(function(){
        console.log(i);
        i++
        fn()  //递归不断调用自己
    },2000);
}
fn()
方法二:
var i = 0;
function fn(){
      var clock = setTimeout(function(){
      console.log(i);
      i++
      clock = setTimeout(arguments.callee,2000); //递归不断调用自己
    },2000);
}
fn()
每隔两秒输出:0,1,2,3,4,5,6~~~~~~~~~~
需要注意的是,使用setTimeout并不能完全模拟出setInterval的功能。
在问答1中介绍过,setTimeout是等前面的任务执行之后再开始计算时间间隔。
而setInterval函数指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间,比如,
setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会
开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。

6.写一个函数,计算setTimeout平均[备注:新加]最小时间粒度(参考)

function getMini() { 
    var t1 = Date.now(); //开始执行函数的时间 
    var i = 0; 
    var clock = setTimeout(function(){ 
          i++; 
      if(i === 1000) { //计算1000次 
          clearTimeout(clock); //停止 
          var t2 = Date.now(); //结束时间 
          console.log((t2-t1)/i); //平均值得到最小粒度 
      }else{

      //arguments 当前函数的参数"数组" 
      //arguments.callee 调用这个"数组"的函数,也就是当前函数 
      //相当于循环执行当前函数, 直到 i 满足判断语句中的值 
          clock = setTimeout(arguments.callee,0);
      } 
  },0) //此处一定是0,无间隔地循环执行直到到1000为止
}
getMini()
输出大约4.249秒~4.5秒

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

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

结果:
2.png

setTimeout的delay值被设为0,也就意味着里面的函数要等待其他语句全部执行完毕才会运行,setTimeout( ,0),代码会在最后执行。所以最先输出的是1,然后赋值3给a,最后执行setTimeout()里面的代码


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

题目:
var flag = true;
setTimeout(function(){ 
    flag = false;
},0)
while(flag){}
console.log(flag);
------------------
等同于
var flag = true;
while(flag){}  //一直卡在这位置不往下执行了
console.log(flag)
setTimeout(function(){
    flag = false
})

分析:只要while(expression){statement},ex条件一直为true,那么就不断循环执行st,setTimeout的delay值被设为0,也就意味着里面的函数要等待其他语句全部执行完毕才开始再运行。而while(flag){}因为flag为true的关系永远不会停止,所以console.log(flag)也就永远不会执行。


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

题目:
for(var i=0;i<5;i++){ 
    setTimeout(function(){ 
      console.log('delayer:' + i ); 
    }, 0); 
   console.log(i);
}
结果3.png

解答:用闭包保存循环中每次的i值,闭包只是起到保存变量的作用,并未因此改变setTimeout( ,0)中的代码依然放置事件队列最尾处才执行的规则

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

结果3.png

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

结果3.png

方法三:
for(var i=0;i<5;i++){
  fn = function(n){
    return function(){
      console.log("delayer:"+n)
    }
  }(i)
  setTimeout(fn,0)
  console.log(i)
}
结果3.png

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

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

推荐阅读更多精彩内容

  • 问题 一、什么是闭包? 有什么作用? 闭包闭包就是能够读取其他函数内部变量的函数。在javascript中,只有函...
    婷楼沐熙阅读 569评论 0 0
  • 什么是闭包? 有什么作用闭包:函数对象可以通过作用域链相互关联,函数体内部的变量可以保存在函数的作用域内。 上述代...
    coolheadedY阅读 716评论 0 0
  • 本教程版权归小圆和饥人谷所有,转载须说明来源 问题 什么是闭包? 有什么作用闭包(closure)是指有权访问另一...
    饥人谷__小圆阅读 489评论 0 0
  • 1.什么是闭包? 有什么作用 闭包指有权访问另一个函数作用域的变量的函数。创建闭包的常见方式 是 在一个函数...
    JunVincetHuo阅读 1,360评论 0 2
  • 我终于认识到,或者说相信,在我们中一些人看来,自由和安静对自己是必须争取和维护的特权,对他人则是个无关紧要的名词,...
    马丁路子阅读 387评论 0 1