Js 闭包、定时器

问题

什么是闭包? 有什么作用

闭包可以用来读取函数内部的变量。

function f1() {
  var n = 999;
  function f2() {
    console.log(n);
  }
  return f2;
}

var result = f1();
result(); //999

由于作用域链表,外部是无法读取到函数内部的变量的。所以如果想要得到函数内部的变量,可以在函数体内部再定义一个函数,这个用这个函数返回所需要的变量。

function create_counter(initial) { 
    var x = initial || 0; 
    return { inc: function () { 
    x += 1; 
    return x; 
    } 
}}

var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
  • 上面例子中,c1,c2引用的外部函数的x,是独立的两个值,封闭的包装。
  • 闭包可以理解为是携带状态的函数,并且它的状态可以完全对外隐藏起来。

setTimeout 0 有什么作用

setTimeout(f, 0) ; 将第二个参数设为 0,作用是让 f 在现有的任务(脚本的同步任务和“消息队列”指定的任务)一结束就立刻执行。也就是说,setTimeout(f, 0)的作用是,尽可能早地执行指定的任务,而并不是会立刻就执行这个任务。

  • 可以用于调整事件的发生顺序;
  • 将一些消耗性能的任务,分成小块放到setTimeout(f, 0)中,可以减轻性能压力。

代码题

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

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

这段代码输出10。上段循环中,将一个函数,依次写进一个数组中,而这个函数不是立即执行的,通过fnArr[]()调用,才进行执行。所以当循环结束后,此时i的数值已经变化为10,当调用fnArr[3](),实际上执行的是return i ; ,而此时的 i 就是 10。

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

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

function car(){
  var speed = 0;
  return {
    setSpeed:function(val){
      speed = val;
      return speed;
    },
    getSpeed:function(){
      console.log(speed);
      return speed;
    },
    accelerate:function(){
      speed += 10;
    },
    decelerate:function(){
      speed -= 10;
      if (speed < 0){
        speed = 0;
      } 
    },
    getStatus:function(){
      if(speed!==0){
        console.log('running');
        return 'running';
      }
      else {
        console.log('stoped');
        return 'stoped';
      }
    }
  };
}

var Car = car();

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;  //undefined;

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

var i = 0;
function interval(){
  setTimeout(function(){
    console.log(i++);
    interval();
  },1000);
}
interval();

写一个函数,计算setTimeout最小时间粒度

function getMini(){
  var i = 0;
  var start = Date.now();
  var timer = setTimeout(function(){
    i++;
    if(i === 1000){
      clearTimeout(timer);
      var end = Date.now();
      console.log((end-start)/i);
    }
    timer = setTimeout(arguments.callee,0);
  },0);
}
getMini();//4.112//4.117

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

var a = 1;
setTimeout(function(){
    a = 2;
    console.log(a);//3执行
}, 0);
var a ;
console.log(a);  //1执行
a = 3;
console.log(a);//2执行
//1  3  2
  • setTimeout(func,0) 会将任务在下一个Event Loop之前执行,所以这里的function被移到了最后进行执行。

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

var flag = true;
setTimeout(function(){
    flag = false;
},0);//理论上不会执行
while(flag){}
console.log(flag);//理论上不会执行
  • setTimeout将function移到下一个Event Loop之前执行,但是while将这个阻断了,陷入了无限循环。所以flag不能被赋值成false。这也说明程序的运行是单线程的。

下面这段代码输出?如何输出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(num){
      setTimeout(function(){
         console.log('delayer:' + num );
    }, 0);
    })(i);
    console.log(i);
}

本教程版权归 张宇 及 饥人谷 所有,转载请标明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 什么是闭包? 有什么作用闭包:函数对象可以通过作用域链相互关联,函数体内部的变量可以保存在函数的作用域内。 上述代...
    coolheadedY阅读 754评论 0 0
  • 一、问题 (一)、什么是闭包? 有什么作用 闭包是指能够访问自由变量的函数 (变量在本地使用,但在闭包中定义)。换...
    该帐号已被查封_才怪阅读 401评论 0 1
  • 1: 下面的代码输出多少?修改代码让 fnArri 输出 i。使用 两种以上的方法 输出结果为10,因为retur...
    DeeJay_Y阅读 365评论 0 0
  • 1.什么是闭包? 有什么作用 函数的作用域scope取决于声明时,而非调用时。普通函数执行后函数体及内部变量会被垃...
    泰格_R阅读 634评论 0 1
  • 孩子的童年是一张填充图册,早有绚丽的框架,只是需要和他们一起去填充。 放假的那天,晶晶问我:暑假打算带孩子去哪啊?...
    左清水阅读 534评论 2 3